Update libpng from 1.6.3 to 1.6.10
Change-Id: I76e81e7fd267d15991cd342c5caeb2fe77964ebf
diff --git a/contrib/libtests/pngunknown.c b/contrib/libtests/pngunknown.c
index 25452db..b8c4899 100644
--- a/contrib/libtests/pngunknown.c
+++ b/contrib/libtests/pngunknown.c
@@ -1,8 +1,8 @@
/* pngunknown.c - test the read side unknown chunk handling
*
- * Last changed in libpng 1.6.0 [February 14, 2013]
- * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.10 [March 6, 2014]
+ * Copyright (c) 2014 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
* This code is released under the libpng license.
@@ -30,7 +30,19 @@
# include "../../png.h"
#endif
-#ifdef PNG_READ_SUPPORTED
+/* Since this program tests the ability to change the unknown chunk handling
+ * these must be defined:
+ */
+#if defined(PNG_SET_UNKNOWN_CHUNKS_SUPPORTED) &&\
+ defined(PNG_READ_SUPPORTED)
+
+/* One of these must be defined to allow us to find out what happened. It is
+ * still useful to set unknown chunk handling without either of these in order
+ * to cause *known* chunks to be discarded. This can be a significant
+ * efficiency gain, but it can't really be tested here.
+ */
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) ||\
+ defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
#if PNG_LIBPNG_VER < 10500
/* This deliberately lacks the PNG_CONST. */
@@ -75,43 +87,74 @@
# define png_const_structp png_structp
#endif
+#if PNG_LIBPNG_VER < 10700
+ /* Copied from libpng 1.7.0 png.h */
+#define PNG_u2(b1, b2) (((unsigned int)(b1) << 8) + (b2))
-/* Copied from pngpriv.h */
-#define PNG_32b(b,s) ((png_uint_32)(b) << (s))
-#define PNG_CHUNK(b1,b2,b3,b4) \
- (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))
+#define PNG_U16(b1, b2) ((png_uint_16)PNG_u2(b1, b2))
+#define PNG_U32(b1, b2, b3, b4)\
+ (((png_uint_32)PNG_u2(b1, b2) << 16) + PNG_u2(b3, b4))
-#define png_IHDR PNG_CHUNK( 73, 72, 68, 82)
-#define png_IDAT PNG_CHUNK( 73, 68, 65, 84)
-#define png_IEND PNG_CHUNK( 73, 69, 78, 68)
-#define png_PLTE PNG_CHUNK( 80, 76, 84, 69)
-#define png_bKGD PNG_CHUNK( 98, 75, 71, 68)
-#define png_cHRM PNG_CHUNK( 99, 72, 82, 77)
-#define png_gAMA PNG_CHUNK(103, 65, 77, 65)
-#define png_hIST PNG_CHUNK(104, 73, 83, 84)
-#define png_iCCP PNG_CHUNK(105, 67, 67, 80)
-#define png_iTXt PNG_CHUNK(105, 84, 88, 116)
-#define png_oFFs PNG_CHUNK(111, 70, 70, 115)
-#define png_pCAL PNG_CHUNK(112, 67, 65, 76)
-#define png_sCAL PNG_CHUNK(115, 67, 65, 76)
-#define png_pHYs PNG_CHUNK(112, 72, 89, 115)
-#define png_sBIT PNG_CHUNK(115, 66, 73, 84)
-#define png_sPLT PNG_CHUNK(115, 80, 76, 84)
-#define png_sRGB PNG_CHUNK(115, 82, 71, 66)
-#define png_sTER PNG_CHUNK(115, 84, 69, 82)
-#define png_tEXt PNG_CHUNK(116, 69, 88, 116)
-#define png_tIME PNG_CHUNK(116, 73, 77, 69)
-#define png_tRNS PNG_CHUNK(116, 82, 78, 83)
-#define png_zTXt PNG_CHUNK(122, 84, 88, 116)
-#define png_vpAg PNG_CHUNK('v', 'p', 'A', 'g')
+/* Constants for known chunk types.
+ */
+#define png_IDAT PNG_U32( 73, 68, 65, 84)
+#define png_IEND PNG_U32( 73, 69, 78, 68)
+#define png_IHDR PNG_U32( 73, 72, 68, 82)
+#define png_PLTE PNG_U32( 80, 76, 84, 69)
+#define png_bKGD PNG_U32( 98, 75, 71, 68)
+#define png_cHRM PNG_U32( 99, 72, 82, 77)
+#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */
+#define png_gAMA PNG_U32(103, 65, 77, 65)
+#define png_gIFg PNG_U32(103, 73, 70, 103)
+#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */
+#define png_gIFx PNG_U32(103, 73, 70, 120)
+#define png_hIST PNG_U32(104, 73, 83, 84)
+#define png_iCCP PNG_U32(105, 67, 67, 80)
+#define png_iTXt PNG_U32(105, 84, 88, 116)
+#define png_oFFs PNG_U32(111, 70, 70, 115)
+#define png_pCAL PNG_U32(112, 67, 65, 76)
+#define png_pHYs PNG_U32(112, 72, 89, 115)
+#define png_sBIT PNG_U32(115, 66, 73, 84)
+#define png_sCAL PNG_U32(115, 67, 65, 76)
+#define png_sPLT PNG_U32(115, 80, 76, 84)
+#define png_sRGB PNG_U32(115, 82, 71, 66)
+#define png_sTER PNG_U32(115, 84, 69, 82)
+#define png_tEXt PNG_U32(116, 69, 88, 116)
+#define png_tIME PNG_U32(116, 73, 77, 69)
+#define png_tRNS PNG_U32(116, 82, 78, 83)
+#define png_zTXt PNG_U32(122, 84, 88, 116)
/* Test on flag values as defined in the spec (section 5.4): */
-#define PNG_CHUNK_ANCILLARY(c ) (1 & ((c) >> 29))
+#define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29))
#define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c))
#define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21))
#define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13))
#define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5))
+#endif /* PNG_LIBPNG_VER < 10700 */
+
+#ifdef __cplusplus
+# define this not_the_cpp_this
+# define new not_the_cpp_new
+# define voidcast(type, value) static_cast<type>(value)
+#else
+# define voidcast(type, value) (value)
+#endif /* __cplusplus */
+
+/* Unused formal parameter errors are removed using the following macro which is
+ * expected to have no bad effects on performance.
+ */
+#ifndef UNUSED
+# if defined(__GNUC__) || defined(_MSC_VER)
+# define UNUSED(param) (void)param;
+# else
+# define UNUSED(param)
+# endif
+#endif
+
+/* Types of chunks not known to libpng */
+#define png_vpAg PNG_U32(118, 112, 65, 103)
+
/* Chunk information */
#define PNG_INFO_tEXt 0x10000000U
#define PNG_INFO_iTXt 0x20000000U
@@ -139,8 +182,8 @@
{ "PLTE", PNG_INFO_PLTE, png_PLTE, 0, 0, ABSENT, 0 },
/* Non-critical chunks that libpng handles */
- /* This is a mess but it seems to be the only way to do it - there is no way to
- * check for definition outside a #if.
+ /* This is a mess but it seems to be the only way to do it - there is no way
+ * to check for a definition outside a #if.
*/
{ "bKGD", PNG_INFO_bKGD, png_bKGD,
# ifdef PNG_READ_bKGD_SUPPORTED
@@ -317,14 +360,16 @@
static int
ancillary(const char *name)
{
- return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3]));
+ return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3]));
}
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static int
ancillaryb(const png_byte *name)
{
- return PNG_CHUNK_ANCILLARY(PNG_CHUNK(name[0], name[1], name[2], name[3]));
+ return PNG_CHUNK_ANCILLARY(PNG_U32(name[0], name[1], name[2], name[3]));
}
+#endif
/* Type of an error_ptr */
typedef struct
@@ -332,8 +377,11 @@
jmp_buf error_return;
png_structp png_ptr;
png_infop info_ptr, end_ptr;
+ png_uint_32 before_IDAT;
+ png_uint_32 after_IDAT;
int error_count;
int warning_count;
+ int keep; /* the default value */
const char *program;
const char *file;
const char *test;
@@ -366,9 +414,6 @@
d->test);
exit(1);
}
-
- /* Invalidate the test */
- d->test = init;
}
PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN)
@@ -394,7 +439,7 @@
}
/* libpng error and warning callbacks */
-PNG_FUNCTION(void, error, (png_structp png_ptr, const char *message),
+PNG_FUNCTION(void, (PNGCBAPI error), (png_structp png_ptr, const char *message),
static PNG_NORETURN)
{
display *d = (display*)png_get_error_ptr(png_ptr);
@@ -403,7 +448,7 @@
display_exit(d);
}
-static void
+static void PNGCBAPI
warning(png_structp png_ptr, const char *message)
{
display *d = (display*)png_get_error_ptr(png_ptr);
@@ -444,11 +489,88 @@
return flags;
}
+#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+static int PNGCBAPI
+read_callback(png_structp pp, png_unknown_chunkp pc)
+{
+ /* This function mimics the behavior of png_set_keep_unknown_chunks by
+ * returning '0' to keep the chunk and '1' to discard it.
+ */
+ display *d = voidcast(display*, png_get_user_chunk_ptr(pp));
+ int chunk = findb(pc->name);
+ int keep, discard;
+
+ if (chunk < 0) /* not one in our list, so not a known chunk */
+ keep = d->keep;
+
+ else
+ {
+ keep = chunk_info[chunk].keep;
+ if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT)
+ {
+ /* See the comments in png.h - use the default for unknown chunks,
+ * do not keep known chunks.
+ */
+ if (chunk_info[chunk].unknown)
+ keep = d->keep;
+
+ else
+ keep = PNG_HANDLE_CHUNK_NEVER;
+ }
+ }
+
+ switch (keep)
+ {
+ default:
+ fprintf(stderr, "%s(%s): %d: unrecognized chunk option\n", d->file,
+ d->test, chunk_info[chunk].keep);
+ display_exit(d);
+
+ case PNG_HANDLE_CHUNK_AS_DEFAULT:
+ case PNG_HANDLE_CHUNK_NEVER:
+ discard = 1/*handled; discard*/;
+ break;
+
+ case PNG_HANDLE_CHUNK_IF_SAFE:
+ case PNG_HANDLE_CHUNK_ALWAYS:
+ discard = 0/*not handled; keep*/;
+ break;
+ }
+
+ /* Also store information about this chunk in the display, the relevant flag
+ * is set if the chunk is to be kept ('not handled'.)
+ */
+ if (chunk >= 0) if (!discard) /* stupidity to stop a GCC warning */
+ {
+ png_uint_32 flag = chunk_info[chunk].flag;
+
+ if (pc->location & PNG_AFTER_IDAT)
+ d->after_IDAT |= flag;
+
+ else
+ d->before_IDAT |= flag;
+ }
+
+ /* However if there is no support to store unknown chunks don't ask libpng to
+ * do it; there will be an png_error.
+ */
+# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ return discard;
+# else
+ return 1; /*handled; discard*/
+# endif
+}
+#endif /* READ_USER_CHUNKS_SUPPORTED */
+
+#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static png_uint_32
-get_unknown(display *d, int def, png_infop info_ptr)
+get_unknown(display *d, png_infop info_ptr, int after_IDAT)
{
/* Create corresponding 'unknown' flags */
png_uint_32 flags = 0;
+
+ UNUSED(after_IDAT)
+
{
png_unknown_chunkp unknown;
int num_unknown = png_get_unknown_chunks(d->png_ptr, info_ptr, &unknown);
@@ -458,16 +580,16 @@
int chunk = findb(unknown[num_unknown].name);
/* Chunks not known to pngunknown must be validated here; since they
- * must also be unknown to libpng the 'def' behavior should have been
- * used.
+ * must also be unknown to libpng the 'display->keep' behavior should
+ * have been used.
*/
- if (chunk < 0) switch (def)
+ if (chunk < 0) switch (d->keep)
{
default: /* impossible */
case PNG_HANDLE_CHUNK_AS_DEFAULT:
case PNG_HANDLE_CHUNK_NEVER:
fprintf(stderr, "%s(%s): %s: %s: unknown chunk saved\n",
- d->file, d->test, def ? "discard" : "default",
+ d->file, d->test, d->keep ? "discard" : "default",
unknown[num_unknown].name);
++(d->error_count);
break;
@@ -493,14 +615,39 @@
return flags;
}
+#else
+static png_uint_32
+get_unknown(display *d, png_infop info_ptr, int after_IDAT)
+ /* Otherwise this will return the cached values set by any user callback */
+{
+ UNUSED(info_ptr);
+
+ if (after_IDAT)
+ return d->after_IDAT;
+
+ else
+ return d->before_IDAT;
+}
+
+# ifndef PNG_READ_USER_CHUNKS_SUPPORTED
+ /* The #defines above should mean this is never reached, it's just here as
+ * a check to ensure the logic is correct.
+ */
+# error No store support and no user chunk support, this will not work
+# endif
+#endif
static int
check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
- display *d)
+ display *d, int set_callback)
{
- int i, def = PNG_HANDLE_CHUNK_AS_DEFAULT, npasses, ipass;
+ int i, npasses, ipass;
png_uint_32 height;
+ d->keep = PNG_HANDLE_CHUNK_AS_DEFAULT;
+ d->before_IDAT = 0;
+ d->after_IDAT = 0;
+
/* Some of these errors are permanently fatal and cause an exit here, others
* are per-test and cause an error return.
*/
@@ -526,6 +673,16 @@
png_init_io(d->png_ptr, fp);
+# ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ /* This is only done if requested by the caller; it interferes with the
+ * standard store/save mechanism.
+ */
+ if (set_callback)
+ png_set_read_user_chunk_fn(d->png_ptr, d, read_callback);
+# else
+ UNUSED(set_callback)
+# endif
+
/* Handle each argument in turn; multiple settings are possible for the same
* chunk and multiple calls will occur (the last one should override all
* preceding ones).
@@ -565,13 +722,11 @@
* in this case, so we just check the arguments! This could
* be improved in the future by using the read callback.
*/
-# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
- png_byte name[5];
+ png_byte name[5];
- memcpy(name, chunk_info[chunk].name, 5);
- png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
- chunk_info[chunk].keep = option;
-# endif
+ memcpy(name, chunk_info[chunk].name, 5);
+ png_set_keep_unknown_chunks(d->png_ptr, option, name, 1);
+ chunk_info[chunk].keep = option;
continue;
}
@@ -580,10 +735,8 @@
case 7: /* default */
if (memcmp(argv[i], "default", 7) == 0)
{
-# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
- png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
-# endif
- def = option;
+ png_set_keep_unknown_chunks(d->png_ptr, option, NULL, 0);
+ d->keep = option;
continue;
}
@@ -592,14 +745,12 @@
case 3: /* all */
if (memcmp(argv[i], "all", 3) == 0)
{
-# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
- png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
- def = option;
+ png_set_keep_unknown_chunks(d->png_ptr, option, NULL, -1);
+ d->keep = option;
- for (chunk = 0; chunk < NINFO; ++chunk)
- if (chunk_info[chunk].all)
- chunk_info[chunk].keep = option;
-# endif
+ for (chunk = 0; chunk < NINFO; ++chunk)
+ if (chunk_info[chunk].all)
+ chunk_info[chunk].keep = option;
continue;
}
@@ -673,18 +824,18 @@
png_read_end(d->png_ptr, d->end_ptr);
flags[0] = get_valid(d, d->info_ptr);
- flags[1] = get_unknown(d, def, d->info_ptr);
+ flags[1] = get_unknown(d, d->info_ptr, 0/*before IDAT*/);
/* Only png_read_png sets PNG_INFO_IDAT! */
flags[chunk_info[0/*IDAT*/].keep != PNG_HANDLE_CHUNK_AS_DEFAULT] |=
PNG_INFO_IDAT;
flags[2] = get_valid(d, d->end_ptr);
- flags[3] = get_unknown(d, def, d->end_ptr);
+ flags[3] = get_unknown(d, d->end_ptr, 1/*after IDAT*/);
clean_display(d);
- return def;
+ return d->keep;
}
static void
@@ -705,7 +856,7 @@
static void
check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known,
- png_uint_32 unknown, const char *position)
+ png_uint_32 unknown, const char *position, int set_callback)
{
while (chunks)
{
@@ -812,8 +963,9 @@
if (errorx != NULL)
{
++(d->error_count);
- fprintf(stderr, "%s(%s): %s %s %s: %s\n",
- d->file, d->test, type, chunk_info[i].name, position, errorx);
+ fprintf(stderr, "%s(%s%s): %s %s %s: %s\n", d->file, d->test,
+ set_callback ? ",callback" : "",
+ type, chunk_info[i].name, position, errorx);
}
chunks &= ~flag;
@@ -822,7 +974,7 @@
static void
perform_one_test(FILE *fp, int argc, const char **argv,
- png_uint_32 *default_flags, display *d)
+ png_uint_32 *default_flags, display *d, int set_callback)
{
int def;
png_uint_32 flags[2][4];
@@ -831,7 +983,7 @@
clear_keep();
memcpy(flags[0], default_flags, sizeof flags[0]);
- def = check(fp, argc, argv, flags[1], d);
+ def = check(fp, argc, argv, flags[1], d, set_callback);
/* Chunks should either be known or unknown, never both and this should apply
* whether the chunk is before or after the IDAT (actually, the app can
@@ -866,9 +1018,9 @@
* it or not.
*/
check_handling(d, def, flags[0][0] | flags[0][1], flags[1][0], flags[1][1],
- "before IDAT");
+ "before IDAT", set_callback);
check_handling(d, def, flags[0][2] | flags[0][3], flags[1][2], flags[1][3],
- "after IDAT");
+ "after IDAT", set_callback);
}
static void
@@ -878,7 +1030,12 @@
if (setjmp(d->error_return) == 0)
{
d->test = test; /* allow use of d->error_return */
- perform_one_test(fp, argc, argv, default_flags, d);
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+ perform_one_test(fp, argc, argv, default_flags, d, 0);
+# endif
+# ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ perform_one_test(fp, argc, argv, default_flags, d, 1);
+# endif
d->test = init; /* prevent use of d->error_return */
}
}
@@ -902,7 +1059,7 @@
fprintf(stderr, "pngunknown: %s: usage:\n %s [--strict] "
"--default|{(CHNK|default|all)=(default|discard|if-safe|save)} "
"testfile.png\n", reason, program);
- exit(2);
+ exit(99);
}
int
@@ -950,11 +1107,6 @@
else if (default_tests) if (argc != 1)
usage(d.program, "extra arguments");
-# ifndef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
- fprintf(stderr, "%s: warning: no 'save' support so arguments ignored\n",
- d.program);
-# endif
-
/* The name of the test file is the last argument; remove it. */
d.file = argv[--argc];
@@ -962,24 +1114,40 @@
if (fp == NULL)
{
perror(d.file);
- exit(2);
+ exit(99);
}
/* First find all the chunks, known and unknown, in the test file, a failure
* here aborts the whole test.
+ *
+ * If 'save' is supported then the normal saving method should happen,
+ * otherwise if 'read' is supported then the read callback will do the
+ * same thing. If both are supported the 'read' callback won't be
+ * instantiated by default. If 'save' is *not* supported then a user
+ * callback is required even though we can call png_get_unknown_chunks.
*/
- if (check(fp, 1, &count_argv, default_flags, &d) !=
- PNG_HANDLE_CHUNK_ALWAYS)
+ if (check(fp, 1, &count_argv, default_flags, &d,
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+ 0
+# else
+ 1
+# endif
+ ) != PNG_HANDLE_CHUNK_ALWAYS)
{
fprintf(stderr, "%s: %s: internal error\n", d.program, d.file);
- exit(3);
+ exit(99);
}
/* Now find what the various supplied options cause to change: */
if (!default_tests)
{
d.test = cmd; /* acts as a flag to say exit, do not longjmp */
- perform_one_test(fp, argc, argv, default_flags, &d);
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
+ perform_one_test(fp, argc, argv, default_flags, &d, 0);
+# endif
+# ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ perform_one_test(fp, argc, argv, default_flags, &d, 1);
+# endif
d.test = init;
}
@@ -1037,14 +1205,14 @@
if (fclose(fsuccess) || err)
{
fprintf(stderr, "%s: write failed\n", touch_file);
- exit(1);
+ exit(99);
}
}
else
{
fprintf(stderr, "%s: open failed\n", touch_file);
- exit(1);
+ exit(99);
}
}
@@ -1054,13 +1222,24 @@
return 1;
}
-#else
+#else /* !(READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS) */
int
main(void)
{
fprintf(stderr,
- " test ignored because libpng was not built with unknown chunk support\n");
+ " test ignored: no support to find out about unknown chunks\n");
/* So the test is skipped: */
return 77;
}
-#endif
+#endif /* READ_USER_CHUNKS || SAVE_UNKNOWN_CHUNKS */
+
+#else /* !(SET_UNKNOWN_CHUNKS && READ) */
+int
+main(void)
+{
+ fprintf(stderr,
+ " test ignored: no support to modify unknown chunk handling\n");
+ /* So the test is skipped: */
+ return 77;
+}
+#endif /* SET_UNKNOWN_CHUNKS && READ*/