CRUX
Threads by month
- ----- 2024 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
November 2015
- 14 participants
- 71 discussions
ports/opt (3.2): [notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
by crux@crux.nu 13 Nov '15
by crux@crux.nu 13 Nov '15
13 Nov '15
commit 6d70736819780690643a3285361477e4f244ad9c
Author: Fredrik Rinnestam <fredrik(a)crux.nu>
Date: Fri Nov 13 22:02:51 2015 +0100
[notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
diff --git a/libpng/.footprint b/libpng/.footprint
index ca463c4..f642b36 100644
--- a/libpng/.footprint
+++ b/libpng/.footprint
@@ -18,9 +18,9 @@ lrwxrwxrwx root/root usr/lib/libpng.la -> libpng16.la
lrwxrwxrwx root/root usr/lib/libpng.so -> libpng16.so
-rw-r--r-- root/root usr/lib/libpng16.a
-rwxr-xr-x root/root usr/lib/libpng16.la
-lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.18.0
-lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.18.0
--rwxr-xr-x root/root usr/lib/libpng16.so.16.18.0
+lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.19.0
+lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.19.0
+-rwxr-xr-x root/root usr/lib/libpng16.so.16.19.0
drwxr-xr-x root/root usr/lib/pkgconfig/
lrwxrwxrwx root/root usr/lib/pkgconfig/libpng.pc -> libpng16.pc
-rw-r--r-- root/root usr/lib/pkgconfig/libpng16.pc
diff --git a/libpng/.md5sum b/libpng/.md5sum
index 44202c0..83d9f03 100644
--- a/libpng/.md5sum
+++ b/libpng/.md5sum
@@ -1,2 +1,2 @@
-a9c85fe3cf0347ea94356f1e70d07973 libpng-1.6.18-apng.patch.gz
-6a57c8e0f5469b9c9949a4b43d57b3a1 libpng-1.6.18.tar.xz
+4991e8e3a79d9aaefc4106b4a3c7e13e libpng-1.6.19-apng.patch
+1e6a458429e850fc93c1f3b6dc00a48f libpng-1.6.19.tar.xz
diff --git a/libpng/Pkgfile b/libpng/Pkgfile
index 3f222c0..d0e7e45 100644
--- a/libpng/Pkgfile
+++ b/libpng/Pkgfile
@@ -4,14 +4,14 @@
# Depends on: zlib
name=libpng
-version=1.6.18
+version=1.6.19
release=1
source=(http://download.sourceforge.net/$name/$name-$version.tar.xz \
- http://downloads.sourceforge.net/project/libpng-apng/libpng16/$version/$nam…)
+ $name-$version-apng.patch)
build() {
cd $name-$version
- zcat $SRC/$name-$version-apng.patch.gz | patch -p1
+ patch -p1 -i $SRC/$name-$version-apng.patch
./configure --prefix=/usr --mandir=/usr/man
make
diff --git a/libpng/libpng-1.6.19-apng.patch b/libpng/libpng-1.6.19-apng.patch
new file mode 100644
index 0000000..811d1e3
--- /dev/null
+++ b/libpng/libpng-1.6.19-apng.patch
@@ -0,0 +1,1699 @@
+diff -Nru libpng-1.6.19-orig/pngget.c libpng-1.6.19/pngget.c
+--- libpng-1.6.19-orig/pngget.c 2015-11-13 21:37:46.357671356 +0100
++++ libpng-1.6.19/pngget.c 2015-11-13 21:38:46.566768235 +0100
+@@ -1216,4 +1216,166 @@
+ # endif
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++ png_debug1(1, "in %s retrieval function", "acTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_acTL) &&
++ num_frames != NULL && num_plays != NULL)
++ {
++ *num_frames = info_ptr->num_frames;
++ *num_plays = info_ptr->num_plays;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_frames()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_frames);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_plays()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_plays);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s retrieval function", "fcTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_fcTL) &&
++ width != NULL && height != NULL &&
++ x_offset != NULL && y_offset != NULL &&
++ delay_num != NULL && delay_den != NULL &&
++ dispose_op != NULL && blend_op != NULL)
++ {
++ *width = info_ptr->next_frame_width;
++ *height = info_ptr->next_frame_height;
++ *x_offset = info_ptr->next_frame_x_offset;
++ *y_offset = info_ptr->next_frame_y_offset;
++ *delay_num = info_ptr->next_frame_delay_num;
++ *delay_den = info_ptr->next_frame_delay_den;
++ *dispose_op = info_ptr->next_frame_dispose_op;
++ *blend_op = info_ptr->next_frame_blend_op;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_width()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_width);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_height()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_height);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_x_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_x_offset);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_y_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_y_offset);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_num()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_num);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_den()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_den);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_dispose_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_dispose_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_blend_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_blend_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr != NULL)
++ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++ PNG_UNUSED(info_ptr)
++
++ return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* READ || WRITE */
+diff -Nru libpng-1.6.19-orig/png.h libpng-1.6.19/png.h
+--- libpng-1.6.19-orig/png.h 2015-11-13 21:37:46.323670172 +0100
++++ libpng-1.6.19/png.h 2015-11-13 21:41:07.687687990 +0100
+@@ -334,6 +334,10 @@
+ # include "pnglibconf.h"
+ #endif
+
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ # include "pngconf.h"
+@@ -429,6 +433,17 @@
+ * See pngconf.h for base types that vary by machine/system
+ */
+
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE 0x00
++#define PNG_DISPOSE_OP_BACKGROUND 0x01
++#define PNG_DISPOSE_OP_PREVIOUS 0x02
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE 0x00
++#define PNG_BLEND_OP_OVER 0x01
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+@@ -750,6 +765,11 @@
+ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+ #if INT_MAX >= 0x8000 /* else this might break */
+ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x10000
++#define PNG_INFO_fcTL 0x20000
++#endif
++
+ #endif
+
+ /* This is used for the transformation routines, as some of them
+@@ -788,6 +808,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++ png_uint_32));
++#endif
+
+ /* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+@@ -3108,6 +3132,74 @@
+ /*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(247, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(248, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(249, png_uint_32, png_get_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(250, png_uint_32, png_set_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(251, png_uint_32, png_get_next_frame_width,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(252, png_uint_32, png_get_next_frame_height,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(253, png_uint_32, png_get_next_frame_x_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_y_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(255, png_uint_16, png_get_next_frame_delay_num,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_den,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_byte, png_get_next_frame_dispose_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_byte, png_get_next_frame_blend_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_byte, png_get_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_32, png_set_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(261, void, png_read_frame_head, (png_structp png_ptr,
++ png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(262, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(263, void, png_write_frame_head, (png_structp png_ptr,
++ png_infop info_ptr, png_bytepp row_pointers,
++ 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_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
++ png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+@@ -3117,7 +3209,11 @@
+ * one to use is one more than this.)
+ */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++ PNG_EXPORT_LAST_ORDINAL(264);
++#else
+ PNG_EXPORT_LAST_ORDINAL(244);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+
+ #ifdef __cplusplus
+diff -Nru libpng-1.6.19-orig/pnginfo.h libpng-1.6.19/pnginfo.h
+--- libpng-1.6.19-orig/pnginfo.h 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pnginfo.h 2015-11-13 21:38:46.567768270 +0100
+@@ -255,5 +255,18 @@
+ png_bytepp row_pointers; /* the image bits */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames; /* including default image */
++ png_uint_32 num_plays;
++ png_uint_32 next_frame_width;
++ png_uint_32 next_frame_height;
++ png_uint_32 next_frame_x_offset;
++ png_uint_32 next_frame_y_offset;
++ png_uint_16 next_frame_delay_num;
++ png_uint_16 next_frame_delay_den;
++ png_byte next_frame_dispose_op;
++ png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Nru libpng-1.6.19-orig/pngpread.c libpng-1.6.19/pngpread.c
+--- libpng-1.6.19-orig/pngpread.c 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpread.c 2015-11-13 21:38:46.567768270 +0100
+@@ -194,6 +194,106 @@
+
+ chunk_name = png_ptr->chunk_name;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0 &&
++ png_ptr->num_frames_read < info_ptr->num_frames)
++ {
++ if (chunk_name == png_IDAT)
++ {
++ /* Discard trailing IDATs for the first frame */
++ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "out of place IDAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ else if (chunk_name == png_fdAT)
++ {
++ if (png_ptr->buffer_size < 4)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ensure_sequence_number(png_ptr, 4);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ {
++ /* Discard trailing fdATs for frames other than the first */
++ if (png_ptr->num_frames_read < 2)
++ png_error(png_ptr, "out of place fdAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ else
++ {
++ /* frame data follows */
++ png_ptr->idat_size = png_ptr->push_length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++ png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++ return;
++ }
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_read_reset(png_ptr);
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ png_error(png_ptr, "missing required fcTL chunk");
++
++ png_read_reinit(png_ptr, info_ptr);
++ png_progressive_read_reset(png_ptr);
++
++ if (png_ptr->frame_info_fn != NULL)
++ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++ return;
++ }
++
++ else
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ return;
++ }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ if (chunk_name == png_IDAT)
+ {
+ if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+@@ -258,6 +358,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+@@ -403,6 +506,30 @@
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+
+ else
+ {
+@@ -533,7 +660,11 @@
+ png_byte chunk_tag[4];
+
+ /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+ PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+@@ -541,17 +672,64 @@
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++ {
++ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++ {
++ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++ return;
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++ "APNG chunks");
++ png_crc_finish(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ }
++ else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+ if (png_ptr->chunk_name != png_IDAT)
++#endif
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ png_error(png_ptr, "Not enough compressed data");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++#endif
++
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0)
++ {
++ png_ensure_sequence_number(png_ptr, 4);
++ png_ptr->idat_size -= 4;
++ }
++#endif
+ }
+
+ if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+@@ -625,6 +803,15 @@
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ /* If the app is not APNG-aware, decode only the first frame */
++ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++ {
++ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++ return;
++ }
++#endif
++
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+@@ -1074,6 +1261,18 @@
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn)
++{
++ png_ptr->frame_info_fn = frame_info_fn;
++ png_ptr->frame_end_fn = frame_end_fn;
++ png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Nru libpng-1.6.19-orig/pngpriv.h libpng-1.6.19/pngpriv.h
+--- libpng-1.6.19-orig/pngpriv.h 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpriv.h 2015-11-13 21:38:46.567768270 +0100
+@@ -537,6 +537,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+ /* 0x4000 (unused) */
+ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL 0x10000
++#define PNG_HAVE_fcTL 0x20000
++#endif
+
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR 0x0001
+@@ -754,6 +758,16 @@
+ #define png_tRNS PNG_U32(116, 82, 78, 83)
+ #define png_zTXt PNG_U32(122, 84, 88, 116)
+
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97, 99, 84, 76)
++#define png_fcTL PNG_U32(102, 99, 84, 76)
++#define png_fdAT PNG_U32(102, 100, 65, 84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN 0x0001
++#define PNG_APNG_APP 0x0002
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+@@ -1453,6 +1467,47 @@
+ */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(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);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++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_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_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_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_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++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_structp png_ptr,
++ png_const_bytep data, png_size_t length),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 */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Nru libpng-1.6.19-orig/pngread.c libpng-1.6.19/pngread.c
+--- libpng-1.6.19-orig/pngread.c 2015-11-13 21:37:46.324670207 +0100
++++ libpng-1.6.19/pngread.c 2015-11-13 21:38:46.568768304 +0100
+@@ -158,6 +158,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = length;
+ break;
+ }
+@@ -247,6 +250,17 @@
+ png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+
++#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_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -254,6 +268,72 @@
+ }
+ #endif /* SEQUENTIAL_READ */
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++ png_debug(0, "Reading frame head");
++
++ if (!(png_ptr->mode & PNG_HAVE_acTL))
++ png_error(png_ptr, "attempt to png_read_frame_head() but "
++ "no acTL present");
++
++ /* do nothing for the main IDAT */
++ if (png_ptr->num_frames_read == 0)
++ return;
++
++ png_read_reset(png_ptr);
++ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ have_chunk_after_DAT = 0;
++ for (;;)
++ {
++ png_uint_32 length = png_read_chunk_header(png_ptr);
++
++ if (png_ptr->chunk_name == png_IDAT)
++ {
++ /* discard trailing IDATs for the first frame */
++ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++ png_crc_finish(png_ptr, length);
++ }
++
++ else if (png_ptr->chunk_name == png_fcTL)
++ {
++ png_handle_fcTL(png_ptr, info_ptr, length);
++ have_chunk_after_DAT = 1;
++ }
++
++ else if (png_ptr->chunk_name == png_fdAT)
++ {
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* discard trailing fdATs for frames other than the first */
++ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++ png_crc_finish(png_ptr, length - 4);
++ else if(png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_ptr->idat_size = length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++
++ break;
++ }
++ else
++ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++ }
++ else
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_crc_finish(png_ptr, length);
++ }
++ }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Nru libpng-1.6.19-orig/pngrutil.c libpng-1.6.19/pngrutil.c
+--- libpng-1.6.19-orig/pngrutil.c 2015-11-13 21:37:46.327670311 +0100
++++ libpng-1.6.19/pngrutil.c 2015-11-13 21:38:46.568768304 +0100
+@@ -824,6 +824,11 @@
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ /* Set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+@@ -2724,6 +2729,179 @@
+ }
+ #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
+@@ -3982,7 +4160,38 @@
+ {
+ uInt avail_in;
+ png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 bytes_to_skip = 0;
++
++ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++ {
++ png_crc_finish(png_ptr, bytes_to_skip);
++ bytes_to_skip = 0;
++
++ png_ptr->idat_size = png_read_chunk_header(png_ptr);
++ if (png_ptr->num_frames_read == 0)
++ {
++ if (png_ptr->chunk_name != png_IDAT)
++ png_error(png_ptr, "Not enough image data");
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->chunk_name != png_fdAT)
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ bytes_to_skip = png_ptr->idat_size;
++ continue;
++ }
+
++ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++ png_ptr->idat_size -= 4;
++ }
++ }
++#else
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+@@ -3994,7 +4203,7 @@
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+@@ -4057,6 +4266,9 @@
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->num_frames_read++;
++#endif
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4495,4 +4707,80 @@
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * 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_structp png_ptr)
++{
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++ png_ptr->mode &= ~PNG_AFTER_IDAT;
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++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;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++ png_ptr->width);
++ if (png_ptr->prev_row)
++ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++ /* Start of interlace block */
++ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++ /* Offset to next interlace block */
++ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++ /* Start of interlace block in the y direction */
++ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++ /* Offset to next interlace block in the y direction */
++ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++ if (png_ptr->interlaced)
++ {
++ if (!(png_ptr->transformations & PNG_INTERLACE))
++ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++ png_pass_ystart[0]) / png_pass_yinc[0];
++ else
++ png_ptr->num_rows = png_ptr->height;
++
++ png_ptr->iwidth = (png_ptr->width +
++ png_pass_inc[png_ptr->pass] - 1 -
++ png_pass_start[png_ptr->pass]) /
++ png_pass_inc[png_ptr->pass];
++ }
++ else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++ {
++ png_ptr->num_rows = png_ptr->height;
++ png_ptr->iwidth = png_ptr->width;
++ }
++ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++ png_error(png_ptr, "inflateReset failed");
++ png_ptr->zstream.avail_in = 0;
++ png_ptr->zstream.next_in = 0;
++ png_ptr->zstream.next_out = png_ptr->row_buf;
++ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++ png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* READ */
+diff -Nru libpng-1.6.19-orig/pngset.c libpng-1.6.19/pngset.c
+--- libpng-1.6.19-orig/pngset.c 2015-11-13 21:37:46.329670381 +0100
++++ libpng-1.6.19/pngset.c 2015-11-13 21:38:46.569768339 +0100
+@@ -241,6 +241,11 @@
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++ /* for non-animated png. this may be overwritten from an acTL chunk later */
++ info_ptr->num_frames = 1;
++#endif
+ }
+
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1094,6 +1099,147 @@
+ }
+ #endif /* sPLT */
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_debug1(1, "in %s storage function", "acTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_acTL() with NULL png_ptr "
++ "or info_ptr ignored");
++ return (0);
++ }
++ if (num_frames == 0)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames zero");
++ return (0);
++ }
++ if (num_frames > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames > 2^31-1");
++ return (0);
++ }
++ if (num_plays > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_plays "
++ "> 2^31-1");
++ return (0);
++ }
++
++ info_ptr->num_frames = num_frames;
++ info_ptr->num_plays = num_plays;
++
++ info_ptr->valid |= PNG_INFO_acTL;
++
++ return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s storage function", "fcTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++ "ignored");
++ return (0);
++ }
++
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ if (blend_op == PNG_BLEND_OP_OVER)
++ {
++ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++ {
++ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++ "and wasteful for opaque images, ignored");
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++ }
++
++ info_ptr->next_frame_width = width;
++ info_ptr->next_frame_height = height;
++ info_ptr->next_frame_x_offset = x_offset;
++ info_ptr->next_frame_y_offset = y_offset;
++ info_ptr->next_frame_delay_num = delay_num;
++ info_ptr->next_frame_delay_den = delay_den;
++ info_ptr->next_frame_dispose_op = dispose_op;
++ info_ptr->next_frame_blend_op = blend_op;
++
++ info_ptr->valid |= PNG_INFO_fcTL;
++
++ return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(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)
++{
++ if (width > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++ if (height > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++ if (x_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++ if (y_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++ if (width + x_offset > png_ptr->first_frame_width ||
++ height + y_offset > png_ptr->first_frame_height)
++ png_error(png_ptr, "dimensions of a frame are greater than"
++ "the ones in IHDR");
++
++ if (dispose_op != PNG_DISPOSE_OP_NONE &&
++ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++ png_error(png_ptr, "invalid dispose_op in fcTL");
++
++ if (blend_op != PNG_BLEND_OP_SOURCE &&
++ blend_op != PNG_BLEND_OP_OVER)
++ png_error(png_ptr, "invalid blend_op in fcTL");
++
++ PNG_UNUSED(delay_num)
++ PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++ png_byte is_hidden)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr == NULL)
++ return 0;
++
++ if (is_hidden)
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ else
++ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++ PNG_UNUSED(info_ptr)
++
++ return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Nru libpng-1.6.19-orig/pngstruct.h libpng-1.6.19/pngstruct.h
+--- libpng-1.6.19-orig/pngstruct.h 2015-11-13 21:37:46.356671321 +0100
++++ libpng-1.6.19/pngstruct.h 2015-11-13 21:38:46.569768339 +0100
+@@ -400,6 +400,27 @@
+ png_byte filter_type;
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 apng_flags;
++ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
++ png_uint_32 first_frame_width;
++ png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 num_frames_read; /* incremented after all image data of */
++ /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_uint_32 num_frames_to_write;
++ png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Nru libpng-1.6.19-orig/pngtest.c libpng-1.6.19/pngtest.c
+--- libpng-1.6.19-orig/pngtest.c 2015-11-13 21:37:46.319670033 +0100
++++ libpng-1.6.19/pngtest.c 2015-11-13 21:48:03.778227241 +0100
+@@ -850,6 +850,10 @@
+ png_uint_32 width, height;
+ int num_pass = 1, pass;
+ int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++#endif
+
+ row_buf = NULL;
+ error_parameters.file_name = inname;
+@@ -1406,6 +1410,89 @@
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ png_uint_32 frame;
++ for (frame = 0; frame < num_frames; frame++)
++ {
++ png_uint_32 frame_width;
++ png_uint_32 frame_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_read_frame_head(read_ptr, read_info_ptr);
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++ {
++ png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++ &frame_width, &frame_height,
++ &x_offset, &y_offset,
++ &delay_num, &delay_den,
++ &dispose_op, &blend_op);
++ }
++ else
++ {
++ frame_width = width;
++ frame_height = height;
++ x_offset = 0;
++ y_offset = 0;
++ delay_num = 1;
++ delay_den = 1;
++ dispose_op = PNG_DISPOSE_OP_NONE;
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++ frame_width, frame_height,
++ x_offset, y_offset,
++ delay_num, delay_den,
++ dispose_op, blend_op);
++#endif
++ for (pass = 0; pass < num_pass; pass++)
++ {
++ pngtest_debug1("Writing row data for pass %d", pass);
++ for (y = 0; y < frame_height; y++)
++ {
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Allocating row buffer (pass %d, y = %ld)...", pass, y);
++ row_buf = (png_bytep)png_malloc(read_ptr,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++ pngtest_debug2("0x%08lx (%ld bytes)", (unsigned long)row_buf,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_decode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_encode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Freeing row buffer (pass %d, y = %ld)", pass, y);
++ png_free(read_ptr, row_buf);
++ row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ }
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++ }
++ }
++ else
++#endif
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ pngtest_debug1("Writing row data for pass %d", pass);
+@@ -1506,6 +1593,20 @@
+ }
+ }
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++ {
++ png_byte is_hidden;
++ pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++ num_frames, num_plays);
++ png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++ is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++ png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++ }
++ }
++#endif
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ {
+ png_unknown_chunkp unknowns;
+diff -Nru libpng-1.6.19-orig/pngwrite.c libpng-1.6.19/pngwrite.c
+--- libpng-1.6.19-orig/pngwrite.c 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pngwrite.c 2015-11-13 21:38:46.570768374 +0100
+@@ -128,6 +128,10 @@
+ * the application continues writing the PNG. So check the 'invalid'
+ * flag here too.
+ */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (info_ptr->valid & PNG_INFO_acTL)
++ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ # ifdef PNG_WRITE_gAMA_SUPPORTED
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
+@@ -365,6 +369,11 @@
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++ png_error(png_ptr, "Not enough frames written");
++#endif
++
+ /* See if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+@@ -1450,6 +1459,43 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++ png_bytepp row_pointers, 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_write_frame_head");
++
++ /* there is a chance this has been set after png_write_info was called,
++ * so it would be set but not written. is there a way to be sure? */
++ if (!(info_ptr->valid & PNG_INFO_acTL))
++ png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++ png_write_reset(png_ptr);
++
++ png_write_reinit(png_ptr, info_ptr, width, height);
++
++ if ( !(png_ptr->num_frames_written == 0 &&
++ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_write_frame_tail");
++
++ png_ptr->num_frames_written++;
++
++ PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ # ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
+diff -Nru libpng-1.6.19-orig/pngwutil.c libpng-1.6.19/pngwutil.c
+--- libpng-1.6.19-orig/pngwutil.c 2015-11-13 21:37:46.349671077 +0100
++++ libpng-1.6.19/pngwutil.c 2015-11-13 21:38:46.570768374 +0100
+@@ -901,6 +901,11 @@
+ /* Write the chunk */
+ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1082,7 +1087,14 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ png_ptr->zstream.next_out = data;
+@@ -1128,7 +1140,15 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ png_ptr->zstream.avail_out = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1941,6 +1961,82 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_byte buf[8];
++
++ png_debug(1, "in png_write_acTL");
++
++ png_ptr->num_frames_to_write = num_frames;
++
++ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++ num_frames--;
++
++ png_save_uint_32(buf, num_frames);
++ png_save_uint_32(buf + 4, num_plays);
++
++ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++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_byte buf[26];
++
++ png_debug(1, "in png_write_fcTL");
++
++ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++ if (png_ptr->num_frames_written == 0 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++
++ /* more error checking */
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_save_uint_32(buf + 4, width);
++ png_save_uint_32(buf + 8, height);
++ png_save_uint_32(buf + 12, x_offset);
++ png_save_uint_32(buf + 16, y_offset);
++ png_save_uint_16(buf + 20, delay_num);
++ png_save_uint_16(buf + 22, delay_den);
++ buf[24] = dispose_op;
++ buf[25] = blend_op;
++
++ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++ png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++ png_const_bytep data, png_size_t length)
++{
++ png_byte buf[4];
++
++ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_write_chunk_data(png_ptr, buf, 4);
++
++ png_write_chunk_data(png_ptr, data, length);
++
++ png_write_chunk_end(png_ptr);
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -2706,4 +2802,39 @@
+ }
+ #endif /* WRITE_FLUSH */
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++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 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++ if (width > png_ptr->first_frame_width ||
++ height > png_ptr->first_frame_height)
++ png_error(png_ptr, "width and/or height for a frame greater than"
++ "the ones in IHDR");
++
++ png_set_IHDR(png_ptr, info_ptr, width, height,
++ info_ptr->bit_depth, info_ptr->color_type,
++ info_ptr->interlace_type, info_ptr->compression_type,
++ info_ptr->filter_type);
++
++ png_ptr->width = width;
++ png_ptr->height = height;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++ png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* WRITE */
+diff -Nru libpng-1.6.19-orig/scripts/symbols.def libpng-1.6.19/scripts/symbols.def
+--- libpng-1.6.19-orig/scripts/symbols.def 2015-11-13 21:37:46.354671251 +0100
++++ libpng-1.6.19/scripts/symbols.def 2015-11-13 21:38:46.570768374 +0100
+@@ -249,3 +249,23 @@
+ png_set_check_for_invalid_index @242
+ png_get_palette_max @243
+ png_set_option @244
++ png_get_acTL @245
++ png_set_acTL @246
++ png_get_num_frames @247
++ png_get_num_plays @248
++ png_get_next_frame_fcTL @249
++ png_set_next_frame_fcTL @250
++ png_get_next_frame_width @251
++ png_get_next_frame_height @252
++ png_get_next_frame_x_offset @253
++ png_get_next_frame_y_offset @254
++ png_get_next_frame_delay_num @255
++ png_get_next_frame_delay_den @256
++ png_get_next_frame_dispose_op @257
++ png_get_next_frame_blend_op @258
++ png_get_first_frame_is_hidden @259
++ png_set_first_frame_is_hidden @260
++ png_read_frame_head @261
++ png_set_progressive_frame_fn @262
++ png_write_frame_head @263
++ png_write_frame_tail @264
1
0
ports/opt (3.1): [notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
by crux@crux.nu 13 Nov '15
by crux@crux.nu 13 Nov '15
13 Nov '15
commit 6d70736819780690643a3285361477e4f244ad9c
Author: Fredrik Rinnestam <fredrik(a)crux.nu>
Date: Fri Nov 13 22:02:51 2015 +0100
[notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
diff --git a/libpng/.footprint b/libpng/.footprint
index ca463c4..f642b36 100644
--- a/libpng/.footprint
+++ b/libpng/.footprint
@@ -18,9 +18,9 @@ lrwxrwxrwx root/root usr/lib/libpng.la -> libpng16.la
lrwxrwxrwx root/root usr/lib/libpng.so -> libpng16.so
-rw-r--r-- root/root usr/lib/libpng16.a
-rwxr-xr-x root/root usr/lib/libpng16.la
-lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.18.0
-lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.18.0
--rwxr-xr-x root/root usr/lib/libpng16.so.16.18.0
+lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.19.0
+lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.19.0
+-rwxr-xr-x root/root usr/lib/libpng16.so.16.19.0
drwxr-xr-x root/root usr/lib/pkgconfig/
lrwxrwxrwx root/root usr/lib/pkgconfig/libpng.pc -> libpng16.pc
-rw-r--r-- root/root usr/lib/pkgconfig/libpng16.pc
diff --git a/libpng/.md5sum b/libpng/.md5sum
index 44202c0..83d9f03 100644
--- a/libpng/.md5sum
+++ b/libpng/.md5sum
@@ -1,2 +1,2 @@
-a9c85fe3cf0347ea94356f1e70d07973 libpng-1.6.18-apng.patch.gz
-6a57c8e0f5469b9c9949a4b43d57b3a1 libpng-1.6.18.tar.xz
+4991e8e3a79d9aaefc4106b4a3c7e13e libpng-1.6.19-apng.patch
+1e6a458429e850fc93c1f3b6dc00a48f libpng-1.6.19.tar.xz
diff --git a/libpng/Pkgfile b/libpng/Pkgfile
index 3f222c0..d0e7e45 100644
--- a/libpng/Pkgfile
+++ b/libpng/Pkgfile
@@ -4,14 +4,14 @@
# Depends on: zlib
name=libpng
-version=1.6.18
+version=1.6.19
release=1
source=(http://download.sourceforge.net/$name/$name-$version.tar.xz \
- http://downloads.sourceforge.net/project/libpng-apng/libpng16/$version/$nam…)
+ $name-$version-apng.patch)
build() {
cd $name-$version
- zcat $SRC/$name-$version-apng.patch.gz | patch -p1
+ patch -p1 -i $SRC/$name-$version-apng.patch
./configure --prefix=/usr --mandir=/usr/man
make
diff --git a/libpng/libpng-1.6.19-apng.patch b/libpng/libpng-1.6.19-apng.patch
new file mode 100644
index 0000000..811d1e3
--- /dev/null
+++ b/libpng/libpng-1.6.19-apng.patch
@@ -0,0 +1,1699 @@
+diff -Nru libpng-1.6.19-orig/pngget.c libpng-1.6.19/pngget.c
+--- libpng-1.6.19-orig/pngget.c 2015-11-13 21:37:46.357671356 +0100
++++ libpng-1.6.19/pngget.c 2015-11-13 21:38:46.566768235 +0100
+@@ -1216,4 +1216,166 @@
+ # endif
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++ png_debug1(1, "in %s retrieval function", "acTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_acTL) &&
++ num_frames != NULL && num_plays != NULL)
++ {
++ *num_frames = info_ptr->num_frames;
++ *num_plays = info_ptr->num_plays;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_frames()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_frames);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_plays()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_plays);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s retrieval function", "fcTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_fcTL) &&
++ width != NULL && height != NULL &&
++ x_offset != NULL && y_offset != NULL &&
++ delay_num != NULL && delay_den != NULL &&
++ dispose_op != NULL && blend_op != NULL)
++ {
++ *width = info_ptr->next_frame_width;
++ *height = info_ptr->next_frame_height;
++ *x_offset = info_ptr->next_frame_x_offset;
++ *y_offset = info_ptr->next_frame_y_offset;
++ *delay_num = info_ptr->next_frame_delay_num;
++ *delay_den = info_ptr->next_frame_delay_den;
++ *dispose_op = info_ptr->next_frame_dispose_op;
++ *blend_op = info_ptr->next_frame_blend_op;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_width()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_width);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_height()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_height);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_x_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_x_offset);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_y_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_y_offset);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_num()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_num);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_den()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_den);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_dispose_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_dispose_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_blend_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_blend_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr != NULL)
++ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++ PNG_UNUSED(info_ptr)
++
++ return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* READ || WRITE */
+diff -Nru libpng-1.6.19-orig/png.h libpng-1.6.19/png.h
+--- libpng-1.6.19-orig/png.h 2015-11-13 21:37:46.323670172 +0100
++++ libpng-1.6.19/png.h 2015-11-13 21:41:07.687687990 +0100
+@@ -334,6 +334,10 @@
+ # include "pnglibconf.h"
+ #endif
+
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ # include "pngconf.h"
+@@ -429,6 +433,17 @@
+ * See pngconf.h for base types that vary by machine/system
+ */
+
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE 0x00
++#define PNG_DISPOSE_OP_BACKGROUND 0x01
++#define PNG_DISPOSE_OP_PREVIOUS 0x02
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE 0x00
++#define PNG_BLEND_OP_OVER 0x01
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+@@ -750,6 +765,11 @@
+ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+ #if INT_MAX >= 0x8000 /* else this might break */
+ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x10000
++#define PNG_INFO_fcTL 0x20000
++#endif
++
+ #endif
+
+ /* This is used for the transformation routines, as some of them
+@@ -788,6 +808,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++ png_uint_32));
++#endif
+
+ /* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+@@ -3108,6 +3132,74 @@
+ /*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(247, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(248, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(249, png_uint_32, png_get_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(250, png_uint_32, png_set_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(251, png_uint_32, png_get_next_frame_width,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(252, png_uint_32, png_get_next_frame_height,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(253, png_uint_32, png_get_next_frame_x_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_y_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(255, png_uint_16, png_get_next_frame_delay_num,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_den,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_byte, png_get_next_frame_dispose_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_byte, png_get_next_frame_blend_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_byte, png_get_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_32, png_set_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(261, void, png_read_frame_head, (png_structp png_ptr,
++ png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(262, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(263, void, png_write_frame_head, (png_structp png_ptr,
++ png_infop info_ptr, png_bytepp row_pointers,
++ 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_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
++ png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+@@ -3117,7 +3209,11 @@
+ * one to use is one more than this.)
+ */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++ PNG_EXPORT_LAST_ORDINAL(264);
++#else
+ PNG_EXPORT_LAST_ORDINAL(244);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+
+ #ifdef __cplusplus
+diff -Nru libpng-1.6.19-orig/pnginfo.h libpng-1.6.19/pnginfo.h
+--- libpng-1.6.19-orig/pnginfo.h 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pnginfo.h 2015-11-13 21:38:46.567768270 +0100
+@@ -255,5 +255,18 @@
+ png_bytepp row_pointers; /* the image bits */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames; /* including default image */
++ png_uint_32 num_plays;
++ png_uint_32 next_frame_width;
++ png_uint_32 next_frame_height;
++ png_uint_32 next_frame_x_offset;
++ png_uint_32 next_frame_y_offset;
++ png_uint_16 next_frame_delay_num;
++ png_uint_16 next_frame_delay_den;
++ png_byte next_frame_dispose_op;
++ png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Nru libpng-1.6.19-orig/pngpread.c libpng-1.6.19/pngpread.c
+--- libpng-1.6.19-orig/pngpread.c 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpread.c 2015-11-13 21:38:46.567768270 +0100
+@@ -194,6 +194,106 @@
+
+ chunk_name = png_ptr->chunk_name;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0 &&
++ png_ptr->num_frames_read < info_ptr->num_frames)
++ {
++ if (chunk_name == png_IDAT)
++ {
++ /* Discard trailing IDATs for the first frame */
++ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "out of place IDAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ else if (chunk_name == png_fdAT)
++ {
++ if (png_ptr->buffer_size < 4)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ensure_sequence_number(png_ptr, 4);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ {
++ /* Discard trailing fdATs for frames other than the first */
++ if (png_ptr->num_frames_read < 2)
++ png_error(png_ptr, "out of place fdAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ else
++ {
++ /* frame data follows */
++ png_ptr->idat_size = png_ptr->push_length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++ png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++ return;
++ }
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_read_reset(png_ptr);
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ png_error(png_ptr, "missing required fcTL chunk");
++
++ png_read_reinit(png_ptr, info_ptr);
++ png_progressive_read_reset(png_ptr);
++
++ if (png_ptr->frame_info_fn != NULL)
++ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++ return;
++ }
++
++ else
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ return;
++ }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ if (chunk_name == png_IDAT)
+ {
+ if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+@@ -258,6 +358,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+@@ -403,6 +506,30 @@
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+
+ else
+ {
+@@ -533,7 +660,11 @@
+ png_byte chunk_tag[4];
+
+ /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+ PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+@@ -541,17 +672,64 @@
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++ {
++ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++ {
++ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++ return;
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++ "APNG chunks");
++ png_crc_finish(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ }
++ else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+ if (png_ptr->chunk_name != png_IDAT)
++#endif
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ png_error(png_ptr, "Not enough compressed data");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++#endif
++
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0)
++ {
++ png_ensure_sequence_number(png_ptr, 4);
++ png_ptr->idat_size -= 4;
++ }
++#endif
+ }
+
+ if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+@@ -625,6 +803,15 @@
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ /* If the app is not APNG-aware, decode only the first frame */
++ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++ {
++ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++ return;
++ }
++#endif
++
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+@@ -1074,6 +1261,18 @@
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn)
++{
++ png_ptr->frame_info_fn = frame_info_fn;
++ png_ptr->frame_end_fn = frame_end_fn;
++ png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Nru libpng-1.6.19-orig/pngpriv.h libpng-1.6.19/pngpriv.h
+--- libpng-1.6.19-orig/pngpriv.h 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpriv.h 2015-11-13 21:38:46.567768270 +0100
+@@ -537,6 +537,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+ /* 0x4000 (unused) */
+ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL 0x10000
++#define PNG_HAVE_fcTL 0x20000
++#endif
+
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR 0x0001
+@@ -754,6 +758,16 @@
+ #define png_tRNS PNG_U32(116, 82, 78, 83)
+ #define png_zTXt PNG_U32(122, 84, 88, 116)
+
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97, 99, 84, 76)
++#define png_fcTL PNG_U32(102, 99, 84, 76)
++#define png_fdAT PNG_U32(102, 100, 65, 84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN 0x0001
++#define PNG_APNG_APP 0x0002
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+@@ -1453,6 +1467,47 @@
+ */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(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);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++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_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_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_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_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++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_structp png_ptr,
++ png_const_bytep data, png_size_t length),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 */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Nru libpng-1.6.19-orig/pngread.c libpng-1.6.19/pngread.c
+--- libpng-1.6.19-orig/pngread.c 2015-11-13 21:37:46.324670207 +0100
++++ libpng-1.6.19/pngread.c 2015-11-13 21:38:46.568768304 +0100
+@@ -158,6 +158,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = length;
+ break;
+ }
+@@ -247,6 +250,17 @@
+ png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+
++#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_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -254,6 +268,72 @@
+ }
+ #endif /* SEQUENTIAL_READ */
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++ png_debug(0, "Reading frame head");
++
++ if (!(png_ptr->mode & PNG_HAVE_acTL))
++ png_error(png_ptr, "attempt to png_read_frame_head() but "
++ "no acTL present");
++
++ /* do nothing for the main IDAT */
++ if (png_ptr->num_frames_read == 0)
++ return;
++
++ png_read_reset(png_ptr);
++ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ have_chunk_after_DAT = 0;
++ for (;;)
++ {
++ png_uint_32 length = png_read_chunk_header(png_ptr);
++
++ if (png_ptr->chunk_name == png_IDAT)
++ {
++ /* discard trailing IDATs for the first frame */
++ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++ png_crc_finish(png_ptr, length);
++ }
++
++ else if (png_ptr->chunk_name == png_fcTL)
++ {
++ png_handle_fcTL(png_ptr, info_ptr, length);
++ have_chunk_after_DAT = 1;
++ }
++
++ else if (png_ptr->chunk_name == png_fdAT)
++ {
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* discard trailing fdATs for frames other than the first */
++ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++ png_crc_finish(png_ptr, length - 4);
++ else if(png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_ptr->idat_size = length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++
++ break;
++ }
++ else
++ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++ }
++ else
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_crc_finish(png_ptr, length);
++ }
++ }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Nru libpng-1.6.19-orig/pngrutil.c libpng-1.6.19/pngrutil.c
+--- libpng-1.6.19-orig/pngrutil.c 2015-11-13 21:37:46.327670311 +0100
++++ libpng-1.6.19/pngrutil.c 2015-11-13 21:38:46.568768304 +0100
+@@ -824,6 +824,11 @@
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ /* Set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+@@ -2724,6 +2729,179 @@
+ }
+ #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
+@@ -3982,7 +4160,38 @@
+ {
+ uInt avail_in;
+ png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 bytes_to_skip = 0;
++
++ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++ {
++ png_crc_finish(png_ptr, bytes_to_skip);
++ bytes_to_skip = 0;
++
++ png_ptr->idat_size = png_read_chunk_header(png_ptr);
++ if (png_ptr->num_frames_read == 0)
++ {
++ if (png_ptr->chunk_name != png_IDAT)
++ png_error(png_ptr, "Not enough image data");
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->chunk_name != png_fdAT)
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ bytes_to_skip = png_ptr->idat_size;
++ continue;
++ }
+
++ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++ png_ptr->idat_size -= 4;
++ }
++ }
++#else
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+@@ -3994,7 +4203,7 @@
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+@@ -4057,6 +4266,9 @@
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->num_frames_read++;
++#endif
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4495,4 +4707,80 @@
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * 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_structp png_ptr)
++{
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++ png_ptr->mode &= ~PNG_AFTER_IDAT;
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++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;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++ png_ptr->width);
++ if (png_ptr->prev_row)
++ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++ /* Start of interlace block */
++ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++ /* Offset to next interlace block */
++ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++ /* Start of interlace block in the y direction */
++ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++ /* Offset to next interlace block in the y direction */
++ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++ if (png_ptr->interlaced)
++ {
++ if (!(png_ptr->transformations & PNG_INTERLACE))
++ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++ png_pass_ystart[0]) / png_pass_yinc[0];
++ else
++ png_ptr->num_rows = png_ptr->height;
++
++ png_ptr->iwidth = (png_ptr->width +
++ png_pass_inc[png_ptr->pass] - 1 -
++ png_pass_start[png_ptr->pass]) /
++ png_pass_inc[png_ptr->pass];
++ }
++ else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++ {
++ png_ptr->num_rows = png_ptr->height;
++ png_ptr->iwidth = png_ptr->width;
++ }
++ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++ png_error(png_ptr, "inflateReset failed");
++ png_ptr->zstream.avail_in = 0;
++ png_ptr->zstream.next_in = 0;
++ png_ptr->zstream.next_out = png_ptr->row_buf;
++ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++ png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* READ */
+diff -Nru libpng-1.6.19-orig/pngset.c libpng-1.6.19/pngset.c
+--- libpng-1.6.19-orig/pngset.c 2015-11-13 21:37:46.329670381 +0100
++++ libpng-1.6.19/pngset.c 2015-11-13 21:38:46.569768339 +0100
+@@ -241,6 +241,11 @@
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++ /* for non-animated png. this may be overwritten from an acTL chunk later */
++ info_ptr->num_frames = 1;
++#endif
+ }
+
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1094,6 +1099,147 @@
+ }
+ #endif /* sPLT */
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_debug1(1, "in %s storage function", "acTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_acTL() with NULL png_ptr "
++ "or info_ptr ignored");
++ return (0);
++ }
++ if (num_frames == 0)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames zero");
++ return (0);
++ }
++ if (num_frames > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames > 2^31-1");
++ return (0);
++ }
++ if (num_plays > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_plays "
++ "> 2^31-1");
++ return (0);
++ }
++
++ info_ptr->num_frames = num_frames;
++ info_ptr->num_plays = num_plays;
++
++ info_ptr->valid |= PNG_INFO_acTL;
++
++ return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s storage function", "fcTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++ "ignored");
++ return (0);
++ }
++
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ if (blend_op == PNG_BLEND_OP_OVER)
++ {
++ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++ {
++ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++ "and wasteful for opaque images, ignored");
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++ }
++
++ info_ptr->next_frame_width = width;
++ info_ptr->next_frame_height = height;
++ info_ptr->next_frame_x_offset = x_offset;
++ info_ptr->next_frame_y_offset = y_offset;
++ info_ptr->next_frame_delay_num = delay_num;
++ info_ptr->next_frame_delay_den = delay_den;
++ info_ptr->next_frame_dispose_op = dispose_op;
++ info_ptr->next_frame_blend_op = blend_op;
++
++ info_ptr->valid |= PNG_INFO_fcTL;
++
++ return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(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)
++{
++ if (width > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++ if (height > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++ if (x_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++ if (y_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++ if (width + x_offset > png_ptr->first_frame_width ||
++ height + y_offset > png_ptr->first_frame_height)
++ png_error(png_ptr, "dimensions of a frame are greater than"
++ "the ones in IHDR");
++
++ if (dispose_op != PNG_DISPOSE_OP_NONE &&
++ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++ png_error(png_ptr, "invalid dispose_op in fcTL");
++
++ if (blend_op != PNG_BLEND_OP_SOURCE &&
++ blend_op != PNG_BLEND_OP_OVER)
++ png_error(png_ptr, "invalid blend_op in fcTL");
++
++ PNG_UNUSED(delay_num)
++ PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++ png_byte is_hidden)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr == NULL)
++ return 0;
++
++ if (is_hidden)
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ else
++ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++ PNG_UNUSED(info_ptr)
++
++ return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Nru libpng-1.6.19-orig/pngstruct.h libpng-1.6.19/pngstruct.h
+--- libpng-1.6.19-orig/pngstruct.h 2015-11-13 21:37:46.356671321 +0100
++++ libpng-1.6.19/pngstruct.h 2015-11-13 21:38:46.569768339 +0100
+@@ -400,6 +400,27 @@
+ png_byte filter_type;
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 apng_flags;
++ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
++ png_uint_32 first_frame_width;
++ png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 num_frames_read; /* incremented after all image data of */
++ /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_uint_32 num_frames_to_write;
++ png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Nru libpng-1.6.19-orig/pngtest.c libpng-1.6.19/pngtest.c
+--- libpng-1.6.19-orig/pngtest.c 2015-11-13 21:37:46.319670033 +0100
++++ libpng-1.6.19/pngtest.c 2015-11-13 21:48:03.778227241 +0100
+@@ -850,6 +850,10 @@
+ png_uint_32 width, height;
+ int num_pass = 1, pass;
+ int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++#endif
+
+ row_buf = NULL;
+ error_parameters.file_name = inname;
+@@ -1406,6 +1410,89 @@
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ png_uint_32 frame;
++ for (frame = 0; frame < num_frames; frame++)
++ {
++ png_uint_32 frame_width;
++ png_uint_32 frame_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_read_frame_head(read_ptr, read_info_ptr);
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++ {
++ png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++ &frame_width, &frame_height,
++ &x_offset, &y_offset,
++ &delay_num, &delay_den,
++ &dispose_op, &blend_op);
++ }
++ else
++ {
++ frame_width = width;
++ frame_height = height;
++ x_offset = 0;
++ y_offset = 0;
++ delay_num = 1;
++ delay_den = 1;
++ dispose_op = PNG_DISPOSE_OP_NONE;
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++ frame_width, frame_height,
++ x_offset, y_offset,
++ delay_num, delay_den,
++ dispose_op, blend_op);
++#endif
++ for (pass = 0; pass < num_pass; pass++)
++ {
++ pngtest_debug1("Writing row data for pass %d", pass);
++ for (y = 0; y < frame_height; y++)
++ {
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Allocating row buffer (pass %d, y = %ld)...", pass, y);
++ row_buf = (png_bytep)png_malloc(read_ptr,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++ pngtest_debug2("0x%08lx (%ld bytes)", (unsigned long)row_buf,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_decode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_encode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Freeing row buffer (pass %d, y = %ld)", pass, y);
++ png_free(read_ptr, row_buf);
++ row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ }
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++ }
++ }
++ else
++#endif
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ pngtest_debug1("Writing row data for pass %d", pass);
+@@ -1506,6 +1593,20 @@
+ }
+ }
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++ {
++ png_byte is_hidden;
++ pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++ num_frames, num_plays);
++ png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++ is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++ png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++ }
++ }
++#endif
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ {
+ png_unknown_chunkp unknowns;
+diff -Nru libpng-1.6.19-orig/pngwrite.c libpng-1.6.19/pngwrite.c
+--- libpng-1.6.19-orig/pngwrite.c 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pngwrite.c 2015-11-13 21:38:46.570768374 +0100
+@@ -128,6 +128,10 @@
+ * the application continues writing the PNG. So check the 'invalid'
+ * flag here too.
+ */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (info_ptr->valid & PNG_INFO_acTL)
++ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ # ifdef PNG_WRITE_gAMA_SUPPORTED
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
+@@ -365,6 +369,11 @@
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++ png_error(png_ptr, "Not enough frames written");
++#endif
++
+ /* See if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+@@ -1450,6 +1459,43 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++ png_bytepp row_pointers, 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_write_frame_head");
++
++ /* there is a chance this has been set after png_write_info was called,
++ * so it would be set but not written. is there a way to be sure? */
++ if (!(info_ptr->valid & PNG_INFO_acTL))
++ png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++ png_write_reset(png_ptr);
++
++ png_write_reinit(png_ptr, info_ptr, width, height);
++
++ if ( !(png_ptr->num_frames_written == 0 &&
++ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_write_frame_tail");
++
++ png_ptr->num_frames_written++;
++
++ PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ # ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
+diff -Nru libpng-1.6.19-orig/pngwutil.c libpng-1.6.19/pngwutil.c
+--- libpng-1.6.19-orig/pngwutil.c 2015-11-13 21:37:46.349671077 +0100
++++ libpng-1.6.19/pngwutil.c 2015-11-13 21:38:46.570768374 +0100
+@@ -901,6 +901,11 @@
+ /* Write the chunk */
+ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1082,7 +1087,14 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ png_ptr->zstream.next_out = data;
+@@ -1128,7 +1140,15 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ png_ptr->zstream.avail_out = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1941,6 +1961,82 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_byte buf[8];
++
++ png_debug(1, "in png_write_acTL");
++
++ png_ptr->num_frames_to_write = num_frames;
++
++ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++ num_frames--;
++
++ png_save_uint_32(buf, num_frames);
++ png_save_uint_32(buf + 4, num_plays);
++
++ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++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_byte buf[26];
++
++ png_debug(1, "in png_write_fcTL");
++
++ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++ if (png_ptr->num_frames_written == 0 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++
++ /* more error checking */
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_save_uint_32(buf + 4, width);
++ png_save_uint_32(buf + 8, height);
++ png_save_uint_32(buf + 12, x_offset);
++ png_save_uint_32(buf + 16, y_offset);
++ png_save_uint_16(buf + 20, delay_num);
++ png_save_uint_16(buf + 22, delay_den);
++ buf[24] = dispose_op;
++ buf[25] = blend_op;
++
++ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++ png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++ png_const_bytep data, png_size_t length)
++{
++ png_byte buf[4];
++
++ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_write_chunk_data(png_ptr, buf, 4);
++
++ png_write_chunk_data(png_ptr, data, length);
++
++ png_write_chunk_end(png_ptr);
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -2706,4 +2802,39 @@
+ }
+ #endif /* WRITE_FLUSH */
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++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 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++ if (width > png_ptr->first_frame_width ||
++ height > png_ptr->first_frame_height)
++ png_error(png_ptr, "width and/or height for a frame greater than"
++ "the ones in IHDR");
++
++ png_set_IHDR(png_ptr, info_ptr, width, height,
++ info_ptr->bit_depth, info_ptr->color_type,
++ info_ptr->interlace_type, info_ptr->compression_type,
++ info_ptr->filter_type);
++
++ png_ptr->width = width;
++ png_ptr->height = height;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++ png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* WRITE */
+diff -Nru libpng-1.6.19-orig/scripts/symbols.def libpng-1.6.19/scripts/symbols.def
+--- libpng-1.6.19-orig/scripts/symbols.def 2015-11-13 21:37:46.354671251 +0100
++++ libpng-1.6.19/scripts/symbols.def 2015-11-13 21:38:46.570768374 +0100
+@@ -249,3 +249,23 @@
+ png_set_check_for_invalid_index @242
+ png_get_palette_max @243
+ png_set_option @244
++ png_get_acTL @245
++ png_set_acTL @246
++ png_get_num_frames @247
++ png_get_num_plays @248
++ png_get_next_frame_fcTL @249
++ png_set_next_frame_fcTL @250
++ png_get_next_frame_width @251
++ png_get_next_frame_height @252
++ png_get_next_frame_x_offset @253
++ png_get_next_frame_y_offset @254
++ png_get_next_frame_delay_num @255
++ png_get_next_frame_delay_den @256
++ png_get_next_frame_dispose_op @257
++ png_get_next_frame_blend_op @258
++ png_get_first_frame_is_hidden @259
++ png_set_first_frame_is_hidden @260
++ png_read_frame_head @261
++ png_set_progressive_frame_fn @262
++ png_write_frame_head @263
++ png_write_frame_tail @264
1
0
ports/opt (3.1): [notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
by crux@crux.nu 13 Nov '15
by crux@crux.nu 13 Nov '15
13 Nov '15
commit 6d70736819780690643a3285361477e4f244ad9c
Author: Fredrik Rinnestam <fredrik(a)crux.nu>
Date: Fri Nov 13 22:02:51 2015 +0100
[notify] libpng: updated to 1.6.19. Fix for CVE-2015-8126
diff --git a/libpng/.footprint b/libpng/.footprint
index ca463c4..f642b36 100644
--- a/libpng/.footprint
+++ b/libpng/.footprint
@@ -18,9 +18,9 @@ lrwxrwxrwx root/root usr/lib/libpng.la -> libpng16.la
lrwxrwxrwx root/root usr/lib/libpng.so -> libpng16.so
-rw-r--r-- root/root usr/lib/libpng16.a
-rwxr-xr-x root/root usr/lib/libpng16.la
-lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.18.0
-lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.18.0
--rwxr-xr-x root/root usr/lib/libpng16.so.16.18.0
+lrwxrwxrwx root/root usr/lib/libpng16.so -> libpng16.so.16.19.0
+lrwxrwxrwx root/root usr/lib/libpng16.so.16 -> libpng16.so.16.19.0
+-rwxr-xr-x root/root usr/lib/libpng16.so.16.19.0
drwxr-xr-x root/root usr/lib/pkgconfig/
lrwxrwxrwx root/root usr/lib/pkgconfig/libpng.pc -> libpng16.pc
-rw-r--r-- root/root usr/lib/pkgconfig/libpng16.pc
diff --git a/libpng/.md5sum b/libpng/.md5sum
index 44202c0..83d9f03 100644
--- a/libpng/.md5sum
+++ b/libpng/.md5sum
@@ -1,2 +1,2 @@
-a9c85fe3cf0347ea94356f1e70d07973 libpng-1.6.18-apng.patch.gz
-6a57c8e0f5469b9c9949a4b43d57b3a1 libpng-1.6.18.tar.xz
+4991e8e3a79d9aaefc4106b4a3c7e13e libpng-1.6.19-apng.patch
+1e6a458429e850fc93c1f3b6dc00a48f libpng-1.6.19.tar.xz
diff --git a/libpng/Pkgfile b/libpng/Pkgfile
index 3f222c0..d0e7e45 100644
--- a/libpng/Pkgfile
+++ b/libpng/Pkgfile
@@ -4,14 +4,14 @@
# Depends on: zlib
name=libpng
-version=1.6.18
+version=1.6.19
release=1
source=(http://download.sourceforge.net/$name/$name-$version.tar.xz \
- http://downloads.sourceforge.net/project/libpng-apng/libpng16/$version/$nam…)
+ $name-$version-apng.patch)
build() {
cd $name-$version
- zcat $SRC/$name-$version-apng.patch.gz | patch -p1
+ patch -p1 -i $SRC/$name-$version-apng.patch
./configure --prefix=/usr --mandir=/usr/man
make
diff --git a/libpng/libpng-1.6.19-apng.patch b/libpng/libpng-1.6.19-apng.patch
new file mode 100644
index 0000000..811d1e3
--- /dev/null
+++ b/libpng/libpng-1.6.19-apng.patch
@@ -0,0 +1,1699 @@
+diff -Nru libpng-1.6.19-orig/pngget.c libpng-1.6.19/pngget.c
+--- libpng-1.6.19-orig/pngget.c 2015-11-13 21:37:46.357671356 +0100
++++ libpng-1.6.19/pngget.c 2015-11-13 21:38:46.566768235 +0100
+@@ -1216,4 +1216,166 @@
+ # endif
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_get_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 *num_frames, png_uint_32 *num_plays)
++{
++ png_debug1(1, "in %s retrieval function", "acTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_acTL) &&
++ num_frames != NULL && num_plays != NULL)
++ {
++ *num_frames = info_ptr->num_frames;
++ *num_plays = info_ptr->num_plays;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_frames(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_frames()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_frames);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_num_plays(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_num_plays()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->num_plays);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s retrieval function", "fcTL");
++
++ if (png_ptr != NULL && info_ptr != NULL &&
++ (info_ptr->valid & PNG_INFO_fcTL) &&
++ width != NULL && height != NULL &&
++ x_offset != NULL && y_offset != NULL &&
++ delay_num != NULL && delay_den != NULL &&
++ dispose_op != NULL && blend_op != NULL)
++ {
++ *width = info_ptr->next_frame_width;
++ *height = info_ptr->next_frame_height;
++ *x_offset = info_ptr->next_frame_x_offset;
++ *y_offset = info_ptr->next_frame_y_offset;
++ *delay_num = info_ptr->next_frame_delay_num;
++ *delay_den = info_ptr->next_frame_delay_den;
++ *dispose_op = info_ptr->next_frame_dispose_op;
++ *blend_op = info_ptr->next_frame_blend_op;
++ return (1);
++ }
++
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_width(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_width()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_width);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_height(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_height()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_height);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_x_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_x_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_x_offset);
++ return (0);
++}
++
++png_uint_32 PNGAPI
++png_get_next_frame_y_offset(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_y_offset()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_y_offset);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_num(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_num()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_num);
++ return (0);
++}
++
++png_uint_16 PNGAPI
++png_get_next_frame_delay_den(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_delay_den()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_delay_den);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_dispose_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_dispose_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_dispose_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_next_frame_blend_op(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_get_next_frame_blend_op()");
++
++ if (png_ptr != NULL && info_ptr != NULL)
++ return (info_ptr->next_frame_blend_op);
++ return (0);
++}
++
++png_byte PNGAPI
++png_get_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr != NULL)
++ return (png_byte)(png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN);
++
++ PNG_UNUSED(info_ptr)
++
++ return 0;
++}
++#endif /* PNG_APNG_SUPPORTED */
+ #endif /* READ || WRITE */
+diff -Nru libpng-1.6.19-orig/png.h libpng-1.6.19/png.h
+--- libpng-1.6.19-orig/png.h 2015-11-13 21:37:46.323670172 +0100
++++ libpng-1.6.19/png.h 2015-11-13 21:41:07.687687990 +0100
+@@ -334,6 +334,10 @@
+ # include "pnglibconf.h"
+ #endif
+
++#define PNG_APNG_SUPPORTED
++#define PNG_READ_APNG_SUPPORTED
++#define PNG_WRITE_APNG_SUPPORTED
++
+ #ifndef PNG_VERSION_INFO_ONLY
+ /* Machine specific configuration. */
+ # include "pngconf.h"
+@@ -429,6 +433,17 @@
+ * See pngconf.h for base types that vary by machine/system
+ */
+
++#ifdef PNG_APNG_SUPPORTED
++/* dispose_op flags from inside fcTL */
++#define PNG_DISPOSE_OP_NONE 0x00
++#define PNG_DISPOSE_OP_BACKGROUND 0x01
++#define PNG_DISPOSE_OP_PREVIOUS 0x02
++
++/* blend_op flags from inside fcTL */
++#define PNG_BLEND_OP_SOURCE 0x00
++#define PNG_BLEND_OP_OVER 0x01
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+@@ -750,6 +765,11 @@
+ #define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+ #if INT_MAX >= 0x8000 /* else this might break */
+ #define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_INFO_acTL 0x10000
++#define PNG_INFO_fcTL 0x20000
++#endif
++
+ #endif
+
+ /* This is used for the transformation routines, as some of them
+@@ -788,6 +808,10 @@
+ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop));
+ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop));
++#ifdef PNG_APNG_SUPPORTED
++typedef PNG_CALLBACK(void, *png_progressive_frame_ptr, (png_structp,
++ png_uint_32));
++#endif
+
+ /* The following callback receives png_uint_32 row_number, int pass for the
+ * png_bytep data of the row. When transforming an interlaced image the
+@@ -3108,6 +3132,74 @@
+ /*******************************************************************************
+ * END OF HARDWARE AND SOFTWARE OPTIONS
+ ******************************************************************************/
++#ifdef PNG_APNG_SUPPORTED
++PNG_EXPORT(245, png_uint_32, png_get_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 *num_frames, png_uint_32 *num_plays));
++
++PNG_EXPORT(246, png_uint_32, png_set_acTL, (png_structp png_ptr,
++ png_infop info_ptr, png_uint_32 num_frames, png_uint_32 num_plays));
++
++PNG_EXPORT(247, png_uint_32, png_get_num_frames, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(248, png_uint_32, png_get_num_plays, (png_structp png_ptr,
++ png_infop info_ptr));
++
++PNG_EXPORT(249, png_uint_32, png_get_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(250, png_uint_32, png_set_next_frame_fcTL,
++ (png_structp png_ptr, png_infop info_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_EXPORT(251, png_uint_32, png_get_next_frame_width,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(252, png_uint_32, png_get_next_frame_height,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(253, png_uint_32, png_get_next_frame_x_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(254, png_uint_32, png_get_next_frame_y_offset,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(255, png_uint_16, png_get_next_frame_delay_num,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(256, png_uint_16, png_get_next_frame_delay_den,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(257, png_byte, png_get_next_frame_dispose_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(258, png_byte, png_get_next_frame_blend_op,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(259, png_byte, png_get_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr));
++PNG_EXPORT(260, png_uint_32, png_set_first_frame_is_hidden,
++ (png_structp png_ptr, png_infop info_ptr, png_byte is_hidden));
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_EXPORT(261, void, png_read_frame_head, (png_structp png_ptr,
++ png_infop info_ptr));
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++PNG_EXPORT(262, void, png_set_progressive_frame_fn, (png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn));
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++PNG_EXPORT(263, void, png_write_frame_head, (png_structp png_ptr,
++ png_infop info_ptr, png_bytepp row_pointers,
++ 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_EXPORT(264, void, png_write_frame_tail, (png_structp png_ptr,
++ png_infop info_ptr));
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++#endif /* PNG_APNG_SUPPORTED */
+
+ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project
+ * defs, and in scripts/symbols.def.
+@@ -3117,7 +3209,11 @@
+ * one to use is one more than this.)
+ */
+ #ifdef PNG_EXPORT_LAST_ORDINAL
++#ifdef PNG_APNG_SUPPORTED
++ PNG_EXPORT_LAST_ORDINAL(264);
++#else
+ PNG_EXPORT_LAST_ORDINAL(244);
++#endif /* PNG_APNG_SUPPORTED */
+ #endif
+
+ #ifdef __cplusplus
+diff -Nru libpng-1.6.19-orig/pnginfo.h libpng-1.6.19/pnginfo.h
+--- libpng-1.6.19-orig/pnginfo.h 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pnginfo.h 2015-11-13 21:38:46.567768270 +0100
+@@ -255,5 +255,18 @@
+ png_bytepp row_pointers; /* the image bits */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames; /* including default image */
++ png_uint_32 num_plays;
++ png_uint_32 next_frame_width;
++ png_uint_32 next_frame_height;
++ png_uint_32 next_frame_x_offset;
++ png_uint_32 next_frame_y_offset;
++ png_uint_16 next_frame_delay_num;
++ png_uint_16 next_frame_delay_den;
++ png_byte next_frame_dispose_op;
++ png_byte next_frame_blend_op;
++#endif
++
+ };
+ #endif /* PNGINFO_H */
+diff -Nru libpng-1.6.19-orig/pngpread.c libpng-1.6.19/pngpread.c
+--- libpng-1.6.19-orig/pngpread.c 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpread.c 2015-11-13 21:38:46.567768270 +0100
+@@ -194,6 +194,106 @@
+
+ chunk_name = png_ptr->chunk_name;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0 &&
++ png_ptr->num_frames_read < info_ptr->num_frames)
++ {
++ if (chunk_name == png_IDAT)
++ {
++ /* Discard trailing IDATs for the first frame */
++ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "out of place IDAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ else if (chunk_name == png_fdAT)
++ {
++ if (png_ptr->buffer_size < 4)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ensure_sequence_number(png_ptr, 4);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ {
++ /* Discard trailing fdATs for frames other than the first */
++ if (png_ptr->num_frames_read < 2)
++ png_error(png_ptr, "out of place fdAT");
++
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ else
++ {
++ /* frame data follows */
++ png_ptr->idat_size = png_ptr->push_length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++ png_ptr->process_mode = PNG_READ_IDAT_MODE;
++
++ return;
++ }
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_read_reset(png_ptr);
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++
++ if (!(png_ptr->mode & PNG_HAVE_fcTL))
++ png_error(png_ptr, "missing required fcTL chunk");
++
++ png_read_reinit(png_ptr, info_ptr);
++ png_progressive_read_reset(png_ptr);
++
++ if (png_ptr->frame_info_fn != NULL)
++ (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read);
++
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++
++ return;
++ }
++
++ else
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++
++ return;
++ }
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ if (chunk_name == png_IDAT)
+ {
+ if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
+@@ -258,6 +358,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+@@ -403,6 +506,30 @@
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ #endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ else if (chunk_name == png_acTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++ else if (chunk_name == png_fcTL)
++ {
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++
++ png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length);
++ }
++
++#endif /* PNG_READ_APNG_SUPPORTED */
+
+ else
+ {
+@@ -533,7 +660,11 @@
+ png_byte chunk_tag[4];
+
+ /* TODO: this code can be commoned up with the same code in push_read */
++#ifdef PNG_READ_APNG_SUPPORTED
++ PNG_PUSH_SAVE_BUFFER_IF_LT(12)
++#else
+ PNG_PUSH_SAVE_BUFFER_IF_LT(8)
++#endif
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+@@ -541,17 +672,64 @@
+ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_fdAT && png_ptr->num_frames_read > 0)
++ {
++ if (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)
++ {
++ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++ return;
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
++ {
++ png_push_save_buffer(png_ptr);
++ return;
++ }
++ png_warning(png_ptr, "Skipping (ignoring) a chunk between "
++ "APNG chunks");
++ png_crc_finish(png_ptr, png_ptr->push_length);
++ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
++ return;
++ }
++ }
++ else
++#endif
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->chunk_name != png_IDAT && png_ptr->num_frames_read == 0)
++#else
+ if (png_ptr->chunk_name != png_IDAT)
++#endif
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ png_error(png_ptr, "Not enough compressed data");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->frame_end_fn != NULL)
++ (*(png_ptr->frame_end_fn))(png_ptr, png_ptr->num_frames_read);
++ png_ptr->num_frames_read++;
++#endif
++
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ if (png_ptr->num_frames_read > 0)
++ {
++ png_ensure_sequence_number(png_ptr, 4);
++ png_ptr->idat_size -= 4;
++ }
++#endif
+ }
+
+ if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0)
+@@ -625,6 +803,15 @@
+ if (!(buffer_length > 0) || buffer == NULL)
+ png_error(png_ptr, "No IDAT data (internal error)");
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ /* If the app is not APNG-aware, decode only the first frame */
++ if (!(png_ptr->apng_flags & PNG_APNG_APP) && png_ptr->num_frames_read > 0)
++ {
++ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++ return;
++ }
++#endif
++
+ /* This routine must process all the data it has been given
+ * before returning, calling the row callback as required to
+ * handle the uncompressed results.
+@@ -1074,6 +1261,18 @@
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+ }
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_set_progressive_frame_fn(png_structp png_ptr,
++ png_progressive_frame_ptr frame_info_fn,
++ png_progressive_frame_ptr frame_end_fn)
++{
++ png_ptr->frame_info_fn = frame_info_fn;
++ png_ptr->frame_end_fn = frame_end_fn;
++ png_ptr->apng_flags |= PNG_APNG_APP;
++}
++#endif
++
+ png_voidp PNGAPI
+ png_get_progressive_ptr(png_const_structrp png_ptr)
+ {
+diff -Nru libpng-1.6.19-orig/pngpriv.h libpng-1.6.19/pngpriv.h
+--- libpng-1.6.19-orig/pngpriv.h 2015-11-13 21:37:46.359671425 +0100
++++ libpng-1.6.19/pngpriv.h 2015-11-13 21:38:46.567768270 +0100
+@@ -537,6 +537,10 @@
+ #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+ /* 0x4000 (unused) */
+ #define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */
++#ifdef PNG_APNG_SUPPORTED
++#define PNG_HAVE_acTL 0x10000
++#define PNG_HAVE_fcTL 0x20000
++#endif
+
+ /* Flags for the transformations the PNG library does on the image data */
+ #define PNG_BGR 0x0001
+@@ -754,6 +758,16 @@
+ #define png_tRNS PNG_U32(116, 82, 78, 83)
+ #define png_zTXt PNG_U32(122, 84, 88, 116)
+
++#ifdef PNG_APNG_SUPPORTED
++#define png_acTL PNG_U32( 97, 99, 84, 76)
++#define png_fcTL PNG_U32(102, 99, 84, 76)
++#define png_fdAT PNG_U32(102, 100, 65, 84)
++
++/* For png_struct.apng_flags: */
++#define PNG_FIRST_FRAME_HIDDEN 0x0001
++#define PNG_APNG_APP 0x0002
++#endif
++
+ /* The following will work on (signed char*) strings, whereas the get_uint_32
+ * macro will fail on top-bit-set values because of the sign extension.
+ */
+@@ -1453,6 +1467,47 @@
+ */
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_ensure_fcTL_is_valid,(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);
++
++#ifdef PNG_READ_APNG_SUPPORTED
++PNG_INTERNAL_FUNCTION(void,png_handle_acTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++PNG_INTERNAL_FUNCTION(void,png_handle_fcTL,(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 length),PNG_EMPTY);
++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_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_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_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_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays),PNG_EMPTY);
++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_structp png_ptr,
++ png_const_bytep data, png_size_t length),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 */
++
+ /* Added at libpng version 1.4.0 */
+ #ifdef PNG_COLORSPACE_SUPPORTED
+ /* These internal functions are for maintaining the colorspace structure within
+diff -Nru libpng-1.6.19-orig/pngread.c libpng-1.6.19/pngread.c
+--- libpng-1.6.19-orig/pngread.c 2015-11-13 21:37:46.324670207 +0100
++++ libpng-1.6.19/pngread.c 2015-11-13 21:38:46.568768304 +0100
+@@ -158,6 +158,9 @@
+
+ else if (chunk_name == png_IDAT)
+ {
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_have_info(png_ptr, info_ptr);
++#endif
+ png_ptr->idat_size = length;
+ break;
+ }
+@@ -247,6 +250,17 @@
+ png_handle_iTXt(png_ptr, info_ptr, length);
+ #endif
+
++#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_unknown(png_ptr, info_ptr, length,
+ PNG_HANDLE_CHUNK_AS_DEFAULT);
+@@ -254,6 +268,72 @@
+ }
+ #endif /* SEQUENTIAL_READ */
+
++#ifdef PNG_READ_APNG_SUPPORTED
++void PNGAPI
++png_read_frame_head(png_structp png_ptr, png_infop info_ptr)
++{
++ png_byte have_chunk_after_DAT; /* after IDAT or after fdAT */
++
++ png_debug(0, "Reading frame head");
++
++ if (!(png_ptr->mode & PNG_HAVE_acTL))
++ png_error(png_ptr, "attempt to png_read_frame_head() but "
++ "no acTL present");
++
++ /* do nothing for the main IDAT */
++ if (png_ptr->num_frames_read == 0)
++ return;
++
++ png_read_reset(png_ptr);
++ png_ptr->flags &= ~PNG_FLAG_ROW_INIT;
++ png_ptr->mode &= ~PNG_HAVE_fcTL;
++
++ have_chunk_after_DAT = 0;
++ for (;;)
++ {
++ png_uint_32 length = png_read_chunk_header(png_ptr);
++
++ if (png_ptr->chunk_name == png_IDAT)
++ {
++ /* discard trailing IDATs for the first frame */
++ if (have_chunk_after_DAT || png_ptr->num_frames_read > 1)
++ png_error(png_ptr, "png_read_frame_head(): out of place IDAT");
++ png_crc_finish(png_ptr, length);
++ }
++
++ else if (png_ptr->chunk_name == png_fcTL)
++ {
++ png_handle_fcTL(png_ptr, info_ptr, length);
++ have_chunk_after_DAT = 1;
++ }
++
++ else if (png_ptr->chunk_name == png_fdAT)
++ {
++ png_ensure_sequence_number(png_ptr, length);
++
++ /* discard trailing fdATs for frames other than the first */
++ if (!have_chunk_after_DAT && png_ptr->num_frames_read > 1)
++ png_crc_finish(png_ptr, length - 4);
++ else if(png_ptr->mode & PNG_HAVE_fcTL)
++ {
++ png_ptr->idat_size = length - 4;
++ png_ptr->mode |= PNG_HAVE_IDAT;
++
++ break;
++ }
++ else
++ png_error(png_ptr, "png_read_frame_head(): out of place fdAT");
++ }
++ else
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ png_crc_finish(png_ptr, length);
++ }
++ }
++}
++#endif /* PNG_READ_APNG_SUPPORTED */
++
+ /* Optional call to update the users info_ptr structure */
+ void PNGAPI
+ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
+diff -Nru libpng-1.6.19-orig/pngrutil.c libpng-1.6.19/pngrutil.c
+--- libpng-1.6.19-orig/pngrutil.c 2015-11-13 21:37:46.327670311 +0100
++++ libpng-1.6.19/pngrutil.c 2015-11-13 21:38:46.568768304 +0100
+@@ -824,6 +824,11 @@
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ /* Set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+@@ -2724,6 +2729,179 @@
+ }
+ #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
+@@ -3982,7 +4160,38 @@
+ {
+ uInt avail_in;
+ png_bytep buffer;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 bytes_to_skip = 0;
++
++ while (png_ptr->idat_size == 0 || bytes_to_skip != 0)
++ {
++ png_crc_finish(png_ptr, bytes_to_skip);
++ bytes_to_skip = 0;
++
++ png_ptr->idat_size = png_read_chunk_header(png_ptr);
++ if (png_ptr->num_frames_read == 0)
++ {
++ if (png_ptr->chunk_name != png_IDAT)
++ png_error(png_ptr, "Not enough image data");
++ }
++ else
++ {
++ if (png_ptr->chunk_name == png_IEND)
++ png_error(png_ptr, "Not enough image data");
++ if (png_ptr->chunk_name != png_fdAT)
++ {
++ png_warning(png_ptr, "Skipped (ignored) a chunk "
++ "between APNG chunks");
++ bytes_to_skip = png_ptr->idat_size;
++ continue;
++ }
+
++ png_ensure_sequence_number(png_ptr, png_ptr->idat_size);
++
++ png_ptr->idat_size -= 4;
++ }
++ }
++#else
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+@@ -3994,7 +4203,7 @@
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+-
++#endif /* PNG_READ_APNG_SUPPORTED */
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+@@ -4057,6 +4266,9 @@
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_ptr->num_frames_read++;
++#endif
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+@@ -4495,4 +4707,80 @@
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+ }
++
++#ifdef PNG_READ_APNG_SUPPORTED
++/* This function is to be called after the main IDAT set has been read and
++ * 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_structp png_ptr)
++{
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++ png_ptr->mode &= ~PNG_AFTER_IDAT;
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++}
++
++void /* PRIVATE */
++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;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
++ png_ptr->info_rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,
++ png_ptr->width);
++ if (png_ptr->prev_row)
++ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
++}
++
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++/* same as png_read_reset() but for the progressive reader */
++void /* PRIVATE */
++png_progressive_read_reset(png_structp png_ptr)
++{
++#ifdef PNG_READ_INTERLACING_SUPPORTED
++ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
++
++ /* Start of interlace block */
++ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
++
++ /* Offset to next interlace block */
++ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
++
++ /* Start of interlace block in the y direction */
++ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
++
++ /* Offset to next interlace block in the y direction */
++ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
++
++ if (png_ptr->interlaced)
++ {
++ if (!(png_ptr->transformations & PNG_INTERLACE))
++ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
++ png_pass_ystart[0]) / png_pass_yinc[0];
++ else
++ png_ptr->num_rows = png_ptr->height;
++
++ png_ptr->iwidth = (png_ptr->width +
++ png_pass_inc[png_ptr->pass] - 1 -
++ png_pass_start[png_ptr->pass]) /
++ png_pass_inc[png_ptr->pass];
++ }
++ else
++#endif /* PNG_READ_INTERLACING_SUPPORTED */
++ {
++ png_ptr->num_rows = png_ptr->height;
++ png_ptr->iwidth = png_ptr->width;
++ }
++ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_ENDED;
++ if (inflateReset(&(png_ptr->zstream)) != Z_OK)
++ png_error(png_ptr, "inflateReset failed");
++ png_ptr->zstream.avail_in = 0;
++ png_ptr->zstream.next_in = 0;
++ png_ptr->zstream.next_out = png_ptr->row_buf;
++ png_ptr->zstream.avail_out = (uInt)PNG_ROWBYTES(png_ptr->pixel_depth,
++ png_ptr->iwidth) + 1;
++}
++#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
++#endif /* PNG_READ_APNG_SUPPORTED */
+ #endif /* READ */
+diff -Nru libpng-1.6.19-orig/pngset.c libpng-1.6.19/pngset.c
+--- libpng-1.6.19-orig/pngset.c 2015-11-13 21:37:46.329670381 +0100
++++ libpng-1.6.19/pngset.c 2015-11-13 21:38:46.569768339 +0100
+@@ -241,6 +241,11 @@
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
++
++#ifdef PNG_APNG_SUPPORTED
++ /* for non-animated png. this may be overwritten from an acTL chunk later */
++ info_ptr->num_frames = 1;
++#endif
+ }
+
+ #ifdef PNG_oFFs_SUPPORTED
+@@ -1094,6 +1099,147 @@
+ }
+ #endif /* sPLT */
+
++#ifdef PNG_APNG_SUPPORTED
++png_uint_32 PNGAPI
++png_set_acTL(png_structp png_ptr, png_infop info_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_debug1(1, "in %s storage function", "acTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_acTL() with NULL png_ptr "
++ "or info_ptr ignored");
++ return (0);
++ }
++ if (num_frames == 0)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames zero");
++ return (0);
++ }
++ if (num_frames > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_frames > 2^31-1");
++ return (0);
++ }
++ if (num_plays > PNG_UINT_31_MAX)
++ {
++ png_warning(png_ptr,
++ "Ignoring attempt to set acTL with num_plays "
++ "> 2^31-1");
++ return (0);
++ }
++
++ info_ptr->num_frames = num_frames;
++ info_ptr->num_plays = num_plays;
++
++ info_ptr->valid |= PNG_INFO_acTL;
++
++ return (1);
++}
++
++/* delay_num and delay_den can hold any 16-bit values including zero */
++png_uint_32 PNGAPI
++png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_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_debug1(1, "in %s storage function", "fcTL");
++
++ if (png_ptr == NULL || info_ptr == NULL)
++ {
++ png_warning(png_ptr,
++ "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
++ "ignored");
++ return (0);
++ }
++
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ if (blend_op == PNG_BLEND_OP_OVER)
++ {
++ if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
++ !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
++ {
++ png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
++ "and wasteful for opaque images, ignored");
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++ }
++
++ info_ptr->next_frame_width = width;
++ info_ptr->next_frame_height = height;
++ info_ptr->next_frame_x_offset = x_offset;
++ info_ptr->next_frame_y_offset = y_offset;
++ info_ptr->next_frame_delay_num = delay_num;
++ info_ptr->next_frame_delay_den = delay_den;
++ info_ptr->next_frame_dispose_op = dispose_op;
++ info_ptr->next_frame_blend_op = blend_op;
++
++ info_ptr->valid |= PNG_INFO_fcTL;
++
++ return (1);
++}
++
++void /* PRIVATE */
++png_ensure_fcTL_is_valid(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)
++{
++ if (width > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
++ if (height > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
++ if (x_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
++ if (y_offset > PNG_UINT_31_MAX)
++ png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
++ if (width + x_offset > png_ptr->first_frame_width ||
++ height + y_offset > png_ptr->first_frame_height)
++ png_error(png_ptr, "dimensions of a frame are greater than"
++ "the ones in IHDR");
++
++ if (dispose_op != PNG_DISPOSE_OP_NONE &&
++ dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
++ dispose_op != PNG_DISPOSE_OP_PREVIOUS)
++ png_error(png_ptr, "invalid dispose_op in fcTL");
++
++ if (blend_op != PNG_BLEND_OP_SOURCE &&
++ blend_op != PNG_BLEND_OP_OVER)
++ png_error(png_ptr, "invalid blend_op in fcTL");
++
++ PNG_UNUSED(delay_num)
++ PNG_UNUSED(delay_den)
++}
++
++png_uint_32 PNGAPI
++png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
++ png_byte is_hidden)
++{
++ png_debug(1, "in png_first_frame_is_hidden()");
++
++ if (png_ptr == NULL)
++ return 0;
++
++ if (is_hidden)
++ png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
++ else
++ png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
++
++ PNG_UNUSED(info_ptr)
++
++ return 1;
++}
++#endif /* PNG_APNG_SUPPORTED */
++
+ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ static png_byte
+ check_location(png_const_structrp png_ptr, int location)
+diff -Nru libpng-1.6.19-orig/pngstruct.h libpng-1.6.19/pngstruct.h
+--- libpng-1.6.19-orig/pngstruct.h 2015-11-13 21:37:46.356671321 +0100
++++ libpng-1.6.19/pngstruct.h 2015-11-13 21:38:46.569768339 +0100
+@@ -400,6 +400,27 @@
+ png_byte filter_type;
+ #endif
+
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 apng_flags;
++ png_uint_32 next_seq_num; /* next fcTL/fdAT chunk sequence number */
++ png_uint_32 first_frame_width;
++ png_uint_32 first_frame_height;
++
++#ifdef PNG_READ_APNG_SUPPORTED
++ png_uint_32 num_frames_read; /* incremented after all image data of */
++ /* a frame is read */
++#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
++ png_progressive_frame_ptr frame_info_fn; /* frame info read callback */
++ png_progressive_frame_ptr frame_end_fn; /* frame data read callback */
++#endif
++#endif
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_uint_32 num_frames_to_write;
++ png_uint_32 num_frames_written;
++#endif
++#endif /* PNG_APNG_SUPPORTED */
++
+ /* New members added in libpng-1.2.0 */
+
+ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+diff -Nru libpng-1.6.19-orig/pngtest.c libpng-1.6.19/pngtest.c
+--- libpng-1.6.19-orig/pngtest.c 2015-11-13 21:37:46.319670033 +0100
++++ libpng-1.6.19/pngtest.c 2015-11-13 21:48:03.778227241 +0100
+@@ -850,6 +850,10 @@
+ png_uint_32 width, height;
+ int num_pass = 1, pass;
+ int bit_depth, color_type;
++#ifdef PNG_APNG_SUPPORTED
++ png_uint_32 num_frames;
++ png_uint_32 num_plays;
++#endif
+
+ row_buf = NULL;
+ error_parameters.file_name = inname;
+@@ -1406,6 +1410,89 @@
+ t_misc += (t_stop - t_start);
+ t_start = t_stop;
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ png_uint_32 frame;
++ for (frame = 0; frame < num_frames; frame++)
++ {
++ png_uint_32 frame_width;
++ png_uint_32 frame_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_read_frame_head(read_ptr, read_info_ptr);
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_fcTL))
++ {
++ png_get_next_frame_fcTL(read_ptr, read_info_ptr,
++ &frame_width, &frame_height,
++ &x_offset, &y_offset,
++ &delay_num, &delay_den,
++ &dispose_op, &blend_op);
++ }
++ else
++ {
++ frame_width = width;
++ frame_height = height;
++ x_offset = 0;
++ y_offset = 0;
++ delay_num = 1;
++ delay_den = 1;
++ dispose_op = PNG_DISPOSE_OP_NONE;
++ blend_op = PNG_BLEND_OP_SOURCE;
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_head(write_ptr, write_info_ptr, (png_bytepp)&row_buf,
++ frame_width, frame_height,
++ x_offset, y_offset,
++ delay_num, delay_den,
++ dispose_op, blend_op);
++#endif
++ for (pass = 0; pass < num_pass; pass++)
++ {
++ pngtest_debug1("Writing row data for pass %d", pass);
++ for (y = 0; y < frame_height; y++)
++ {
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Allocating row buffer (pass %d, y = %ld)...", pass, y);
++ row_buf = (png_bytep)png_malloc(read_ptr,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++ pngtest_debug2("0x%08lx (%ld bytes)", (unsigned long)row_buf,
++ png_get_rowbytes(read_ptr, read_info_ptr));
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
++
++#ifdef PNG_WRITE_SUPPORTED
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_decode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++ png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
++#ifdef PNGTEST_TIMING
++ t_stop = (float)clock();
++ t_encode += (t_stop - t_start);
++ t_start = t_stop;
++#endif
++#endif /* PNG_WRITE_SUPPORTED */
++
++#ifndef SINGLE_ROWBUF_ALLOC
++ pngtest_debug2("Freeing row buffer (pass %d, y = %ld)", pass, y);
++ png_free(read_ptr, row_buf);
++ row_buf = NULL;
++#endif /* !SINGLE_ROWBUF_ALLOC */
++ }
++ }
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_write_frame_tail(write_ptr, write_info_ptr);
++#endif
++ }
++ }
++ else
++#endif
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ pngtest_debug1("Writing row data for pass %d", pass);
+@@ -1506,6 +1593,20 @@
+ }
+ }
+ #endif
++#ifdef PNG_APNG_SUPPORTED
++ if (png_get_valid(read_ptr, read_info_ptr, PNG_INFO_acTL))
++ {
++ if (png_get_acTL(read_ptr, read_info_ptr, &num_frames, &num_plays))
++ {
++ png_byte is_hidden;
++ pngtest_debug2("Handling acTL chunks (frames %ld, plays %ld)",
++ num_frames, num_plays);
++ png_set_acTL(write_ptr, write_info_ptr, num_frames, num_plays);
++ is_hidden = png_get_first_frame_is_hidden(read_ptr, read_info_ptr);
++ png_set_first_frame_is_hidden(write_ptr, write_info_ptr, is_hidden);
++ }
++ }
++#endif
+ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+ {
+ png_unknown_chunkp unknowns;
+diff -Nru libpng-1.6.19-orig/pngwrite.c libpng-1.6.19/pngwrite.c
+--- libpng-1.6.19-orig/pngwrite.c 2015-11-13 21:37:46.348671042 +0100
++++ libpng-1.6.19/pngwrite.c 2015-11-13 21:38:46.570768374 +0100
+@@ -128,6 +128,10 @@
+ * the application continues writing the PNG. So check the 'invalid'
+ * flag here too.
+ */
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (info_ptr->valid & PNG_INFO_acTL)
++ png_write_acTL(png_ptr, info_ptr->num_frames, info_ptr->num_plays);
++#endif
+ #ifdef PNG_GAMMA_SUPPORTED
+ # ifdef PNG_WRITE_gAMA_SUPPORTED
+ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 &&
+@@ -365,6 +369,11 @@
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written != png_ptr->num_frames_to_write)
++ png_error(png_ptr, "Not enough frames written");
++#endif
++
+ /* See if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+@@ -1450,6 +1459,43 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void PNGAPI
++png_write_frame_head(png_structp png_ptr, png_infop info_ptr,
++ png_bytepp row_pointers, 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_write_frame_head");
++
++ /* there is a chance this has been set after png_write_info was called,
++ * so it would be set but not written. is there a way to be sure? */
++ if (!(info_ptr->valid & PNG_INFO_acTL))
++ png_error(png_ptr, "png_write_frame_head(): acTL not set");
++
++ png_write_reset(png_ptr);
++
++ png_write_reinit(png_ptr, info_ptr, width, height);
++
++ if ( !(png_ptr->num_frames_written == 0 &&
++ (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN) ) )
++ png_write_fcTL(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ PNG_UNUSED(row_pointers)
++}
++
++void PNGAPI
++png_write_frame_tail(png_structp png_ptr, png_infop info_ptr)
++{
++ png_debug(1, "in png_write_frame_tail");
++
++ png_ptr->num_frames_written++;
++
++ PNG_UNUSED(info_ptr)
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+
+ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
+ # ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
+diff -Nru libpng-1.6.19-orig/pngwutil.c libpng-1.6.19/pngwutil.c
+--- libpng-1.6.19-orig/pngwutil.c 2015-11-13 21:37:46.349671077 +0100
++++ libpng-1.6.19/pngwutil.c 2015-11-13 21:38:46.570768374 +0100
+@@ -901,6 +901,11 @@
+ /* Write the chunk */
+ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13);
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++ png_ptr->first_frame_width = width;
++ png_ptr->first_frame_height = height;
++#endif
++
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+@@ -1082,7 +1087,14 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
+ png_ptr->mode |= PNG_HAVE_IDAT;
+
+ png_ptr->zstream.next_out = data;
+@@ -1128,7 +1140,15 @@
+ optimize_cmf(data, png_image_size(png_ptr));
+ #endif
+
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ if (png_ptr->num_frames_written == 0)
++# endif
+ png_write_complete_chunk(png_ptr, png_IDAT, data, size);
++# ifdef PNG_WRITE_APNG_SUPPORTED
++ else
++ png_write_fdAT(png_ptr, data, size);
++# endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ png_ptr->zstream.avail_out = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT;
+@@ -1941,6 +1961,82 @@
+ }
+ #endif
+
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_acTL(png_structp png_ptr,
++ png_uint_32 num_frames, png_uint_32 num_plays)
++{
++ png_byte buf[8];
++
++ png_debug(1, "in png_write_acTL");
++
++ png_ptr->num_frames_to_write = num_frames;
++
++ if (png_ptr->apng_flags & PNG_FIRST_FRAME_HIDDEN)
++ num_frames--;
++
++ png_save_uint_32(buf, num_frames);
++ png_save_uint_32(buf + 4, num_plays);
++
++ png_write_complete_chunk(png_ptr, png_acTL, buf, (png_size_t)8);
++}
++
++void /* PRIVATE */
++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_byte buf[26];
++
++ png_debug(1, "in png_write_fcTL");
++
++ if (png_ptr->num_frames_written == 0 && (x_offset != 0 || y_offset != 0))
++ png_error(png_ptr, "x and/or y offset for the first frame aren't 0");
++ if (png_ptr->num_frames_written == 0 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++
++ /* more error checking */
++ png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
++ delay_num, delay_den, dispose_op, blend_op);
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_save_uint_32(buf + 4, width);
++ png_save_uint_32(buf + 8, height);
++ png_save_uint_32(buf + 12, x_offset);
++ png_save_uint_32(buf + 16, y_offset);
++ png_save_uint_16(buf + 20, delay_num);
++ png_save_uint_16(buf + 22, delay_den);
++ buf[24] = dispose_op;
++ buf[25] = blend_op;
++
++ png_write_complete_chunk(png_ptr, png_fcTL, buf, (png_size_t)26);
++
++ png_ptr->next_seq_num++;
++}
++
++void /* PRIVATE */
++png_write_fdAT(png_structp png_ptr,
++ png_const_bytep data, png_size_t length)
++{
++ png_byte buf[4];
++
++ png_write_chunk_header(png_ptr, png_fdAT, (png_uint_32)(4 + length));
++
++ png_save_uint_32(buf, png_ptr->next_seq_num);
++ png_write_chunk_data(png_ptr, buf, 4);
++
++ png_write_chunk_data(png_ptr, data, length);
++
++ png_write_chunk_end(png_ptr);
++
++ png_ptr->next_seq_num++;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
++
+ /* Initializes the row writing capability of libpng */
+ void /* PRIVATE */
+ png_write_start_row(png_structrp png_ptr)
+@@ -2706,4 +2802,39 @@
+ }
+ #endif /* WRITE_FLUSH */
+ }
++
++#ifdef PNG_WRITE_APNG_SUPPORTED
++void /* PRIVATE */
++png_write_reset(png_structp png_ptr)
++{
++ png_ptr->row_number = 0;
++ png_ptr->pass = 0;
++ png_ptr->mode &= ~PNG_HAVE_IDAT;
++}
++
++void /* PRIVATE */
++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 &&
++ (width != png_ptr->first_frame_width ||
++ height != png_ptr->first_frame_height))
++ png_error(png_ptr, "width and/or height in the first frame's fcTL "
++ "don't match the ones in IHDR");
++ if (width > png_ptr->first_frame_width ||
++ height > png_ptr->first_frame_height)
++ png_error(png_ptr, "width and/or height for a frame greater than"
++ "the ones in IHDR");
++
++ png_set_IHDR(png_ptr, info_ptr, width, height,
++ info_ptr->bit_depth, info_ptr->color_type,
++ info_ptr->interlace_type, info_ptr->compression_type,
++ info_ptr->filter_type);
++
++ png_ptr->width = width;
++ png_ptr->height = height;
++ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
++ png_ptr->usr_width = png_ptr->width;
++}
++#endif /* PNG_WRITE_APNG_SUPPORTED */
+ #endif /* WRITE */
+diff -Nru libpng-1.6.19-orig/scripts/symbols.def libpng-1.6.19/scripts/symbols.def
+--- libpng-1.6.19-orig/scripts/symbols.def 2015-11-13 21:37:46.354671251 +0100
++++ libpng-1.6.19/scripts/symbols.def 2015-11-13 21:38:46.570768374 +0100
+@@ -249,3 +249,23 @@
+ png_set_check_for_invalid_index @242
+ png_get_palette_max @243
+ png_set_option @244
++ png_get_acTL @245
++ png_set_acTL @246
++ png_get_num_frames @247
++ png_get_num_plays @248
++ png_get_next_frame_fcTL @249
++ png_set_next_frame_fcTL @250
++ png_get_next_frame_width @251
++ png_get_next_frame_height @252
++ png_get_next_frame_x_offset @253
++ png_get_next_frame_y_offset @254
++ png_get_next_frame_delay_num @255
++ png_get_next_frame_delay_den @256
++ png_get_next_frame_dispose_op @257
++ png_get_next_frame_blend_op @258
++ png_get_first_frame_is_hidden @259
++ png_set_first_frame_is_hidden @260
++ png_read_frame_head @261
++ png_set_progressive_frame_fn @262
++ png_write_frame_head @263
++ png_write_frame_tail @264
1
0
El 12/11/2015 15:44, Wawrzek Niewodniczanski <main(a)wawrzek.name> escribió:
>
> Hi,
>
Hey Wawrzek,
> I wonder if you managed to have desktop locking in Enlightenment (E19)
> without PAM. Trying to lock I see following message.
>
> "No PAM support was build into Enlightenment, so desk locking is disable."
>
I haven't that need currently but I believe you need a third party app to get locking support into E19 without PAM support enabled. Probably xlock/slock or something similar.
> Thanks,
> Wawrzek
>
Regards,
Learning bit by bit
Victor Martinez | http://vjml.es
1
0
Hi,
I wonder if you managed to have desktop locking in Enlightenment (E19)
without PAM. Trying to lock I see following message.
"No PAM support was build into Enlightenment, so desk locking is disable."
Thanks,
Wawrzek
--
Dr Wawrzyniec Niewodniczański or Wawrzek for short
PhD in Quantum Chemistry & MSc in Molecular Engineering
WWW: http://wawrzek.name E-MAIL: jobs(a)wawrzek.name
Linux User #177124
1
0
11 Nov '15
commit 57ec7180ce122a853c1b1ac476f74be7eb11d1ce
Author: Jose V Beneyto <sepen(a)crux.nu>
Date: Wed Nov 11 02:16:08 2015 +0100
[notify] flash-player-plugin: updated to 11.2.202.548
Security update:
https://helpx.adobe.com/security/products/flash-player/apsb15-28.html
diff --git a/flash-player-plugin/.md5sum b/flash-player-plugin/.md5sum
index 7aaa805..b7b150b 100644
--- a/flash-player-plugin/.md5sum
+++ b/flash-player-plugin/.md5sum
@@ -1 +1 @@
-110b35abebf8ebc1331a78976897dfed flash-plugin-11.2.202.540-release.x86_64.rpm
+c99d368656c5ad08eb79f374053a14c4 flash-plugin-11.2.202.548-release.x86_64.rpm
diff --git a/flash-player-plugin/Pkgfile b/flash-player-plugin/Pkgfile
index ffc14c0..3348e1a 100644
--- a/flash-player-plugin/Pkgfile
+++ b/flash-player-plugin/Pkgfile
@@ -5,7 +5,7 @@
# Depends on:
name=flash-player-plugin
-version=11.2.202.540
+version=11.2.202.548
release=1
source=(http://fpdownload.macromedia.com/get/flashplayer/pdc/$version/flash…
1
0
11 Nov '15
commit 57ec7180ce122a853c1b1ac476f74be7eb11d1ce
Author: Jose V Beneyto <sepen(a)crux.nu>
Date: Wed Nov 11 02:16:08 2015 +0100
[notify] flash-player-plugin: updated to 11.2.202.548
Security update:
https://helpx.adobe.com/security/products/flash-player/apsb15-28.html
diff --git a/flash-player-plugin/.md5sum b/flash-player-plugin/.md5sum
index 7aaa805..b7b150b 100644
--- a/flash-player-plugin/.md5sum
+++ b/flash-player-plugin/.md5sum
@@ -1 +1 @@
-110b35abebf8ebc1331a78976897dfed flash-plugin-11.2.202.540-release.x86_64.rpm
+c99d368656c5ad08eb79f374053a14c4 flash-plugin-11.2.202.548-release.x86_64.rpm
diff --git a/flash-player-plugin/Pkgfile b/flash-player-plugin/Pkgfile
index ffc14c0..3348e1a 100644
--- a/flash-player-plugin/Pkgfile
+++ b/flash-player-plugin/Pkgfile
@@ -5,7 +5,7 @@
# Depends on:
name=flash-player-plugin
-version=11.2.202.540
+version=11.2.202.548
release=1
source=(http://fpdownload.macromedia.com/get/flashplayer/pdc/$version/flash…
1
0
11 Nov '15
commit 57ec7180ce122a853c1b1ac476f74be7eb11d1ce
Author: Jose V Beneyto <sepen(a)crux.nu>
Date: Wed Nov 11 02:16:08 2015 +0100
[notify] flash-player-plugin: updated to 11.2.202.548
Security update:
https://helpx.adobe.com/security/products/flash-player/apsb15-28.html
diff --git a/flash-player-plugin/.md5sum b/flash-player-plugin/.md5sum
index 7aaa805..b7b150b 100644
--- a/flash-player-plugin/.md5sum
+++ b/flash-player-plugin/.md5sum
@@ -1 +1 @@
-110b35abebf8ebc1331a78976897dfed flash-plugin-11.2.202.540-release.x86_64.rpm
+c99d368656c5ad08eb79f374053a14c4 flash-plugin-11.2.202.548-release.x86_64.rpm
diff --git a/flash-player-plugin/Pkgfile b/flash-player-plugin/Pkgfile
index ffc14c0..3348e1a 100644
--- a/flash-player-plugin/Pkgfile
+++ b/flash-player-plugin/Pkgfile
@@ -5,7 +5,7 @@
# Depends on:
name=flash-player-plugin
-version=11.2.202.540
+version=11.2.202.548
release=1
source=(http://fpdownload.macromedia.com/get/flashplayer/pdc/$version/flash…
1
0
11 Nov '15
commit 57ec7180ce122a853c1b1ac476f74be7eb11d1ce
Author: Jose V Beneyto <sepen(a)crux.nu>
Date: Wed Nov 11 02:16:08 2015 +0100
[notify] flash-player-plugin: updated to 11.2.202.548
Security update:
https://helpx.adobe.com/security/products/flash-player/apsb15-28.html
diff --git a/flash-player-plugin/.md5sum b/flash-player-plugin/.md5sum
index 7aaa805..b7b150b 100644
--- a/flash-player-plugin/.md5sum
+++ b/flash-player-plugin/.md5sum
@@ -1 +1 @@
-110b35abebf8ebc1331a78976897dfed flash-plugin-11.2.202.540-release.x86_64.rpm
+c99d368656c5ad08eb79f374053a14c4 flash-plugin-11.2.202.548-release.x86_64.rpm
diff --git a/flash-player-plugin/Pkgfile b/flash-player-plugin/Pkgfile
index ffc14c0..3348e1a 100644
--- a/flash-player-plugin/Pkgfile
+++ b/flash-player-plugin/Pkgfile
@@ -5,7 +5,7 @@
# Depends on:
name=flash-player-plugin
-version=11.2.202.540
+version=11.2.202.548
release=1
source=(http://fpdownload.macromedia.com/get/flashplayer/pdc/$version/flash…
1
0
> El 09/11/2015 22:03, Bernd Eggink <monoped(a)sudrala.de> escribió:
> >
> > On 09.11.2015 10:17, Víctor Martínez wrote:
> > > El 09/11/2015 10:01, Bernd Eggink <monoped(a)sudrala.de> escribió:
> > >>
> > >> On 09.11.2015 08:27, Víctor Martínez wrote:
> > >>> ...
> > >>> Hey Bernd,
> > >>> which release did you deploy into the BBB? Generic or optimized for the cubieboard1?
> > >>
> > >> Victor,
> > >>
> > >> I used the generic release. What kind of optimization has been made for
> > >> the cubieboard? Compiler options? Kernel config?
> > >>
> > > All releases aren't related to kernels, they are just rootfs optimized for devices. In this case, they are optimized for the compiler.
> > >
> > > The generic release hasn't any kind of optimization.
> >
> > Hi Victor,
> > are you sure? The generic release I downloaded has exactly the same
> > compiler flags as the cubieboard release.
> >
Hey Bernd,
I'm sure CFLAGS aren't the same for the generic release (crux-arm-rootfs-3.1.tar.xz) which are CFLAGS="-O2 -pipe -mfloat-abi=hard" vs cubieboard optimIzed release (crux-arm-rootfs-3.1-cubieboard.tar.xz) which has CFLAGS="-O2 -pipe -mfloat-abi=hard -fpu=neon -mcpu=cortex-a8 -mtune=cortex-a8".
> > > You can take a look into development section in the ports/core-arm repository, the overlayed pkgutils port has pkgmk.conf where you'll see only hard float support.
> > > In your case, in ports/cubieboard-arm repository you can verify its cflags and see if they fit to the ones used by the BBB (probably they'll do).
> > >> Presently I'm preparing a kernel update to 4.3. and will appreciate any
> > >> hints concerning the parameters (not knowing anything about ARM, I can
> > >> only guess them).
> > >>
> > > You shouldn't get any problems upgrading your kernel, but if you do, feel free to share them to take a look.
> >
> > Problems, indeed... After compiling the kernel I realized that simply
> > replacing the zImage (like with x86 machines) isn't enough; the beagle
> > doesn't boot. I've never done that for an ARM system before, and
> > apparently am missing something fundamental. Is there a simple receipt,
> > or could you point me to a concise documentation of that process?
> >
All devices has its own process for booting the device. I'd take a look to the BBB boot process to verify if it needs something special (building uImage instead of zImage, changing addresses, adding dtb to the image, ...)
Without more info related to the problem is hard to give a hand. Is it reading the image? Does it boot but it halts in the middle of the process (file system used for the root partition is compiled in the kernel instead of a module, CONFIG_DEVTMPFS enabled inside the kernel)?...
It'd be great to move this thread to CRUX-ARM mailing list to avoid noise here.
> > Regards,
> > Bernd
Regards,
Victor Martinez | Learning bit by bit
http://vjml.es
1
0