From a066d49b01fa7d134a946475534d50f62d97225a Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Thu, 14 Nov 2013 09:16:37 -0600 Subject: [PATCH] [master] Imported from libpng-1.6.7.tar --- ANNOUNCE | 75 +++++- CHANGES | 76 ++++++ CMakeLists.txt | 4 +- LICENSE | 4 +- Makefile.am | 37 ++- README | 2 +- arm/arm_init.c | 21 +- arm/filter_neon.S | 10 +- arm/filter_neon_intrinsics.c | 372 ++++++++++++++++++++++++++++++ autogen.sh | 13 +- configure.ac | 8 +- contrib/libtests/pngunknown.c | 353 +++++++++++++++++++++------- contrib/libtests/pngvalid.c | 129 +++++++++-- contrib/pngminim/decoder/makefile | 4 +- contrib/pngminim/encoder/makefile | 4 +- contrib/pngminim/preader/makefile | 4 +- contrib/tools/pngfix.c | 32 ++- libpng-manual.txt | 21 +- libpng.3 | 34 +-- libpngpf.3 | 4 +- png.5 | 2 +- png.c | 11 +- png.h | 26 ++- pngconf.h | 2 +- pngpriv.h | 55 ++++- pngrtran.c | 2 +- pngrutil.c | 15 +- pngtest.c | 14 +- projects/vstudio/readme.txt | 2 +- projects/vstudio/zlib.props | 2 +- scripts/README.txt | 12 +- scripts/def.dfn | 2 +- scripts/libpng-config-head.in | 2 +- scripts/libpng.pc.in | 2 +- scripts/makefile.cegcc | 2 +- scripts/makefile.linux | 2 +- scripts/makefile.msys | 2 +- scripts/makefile.ne12bsd | 2 +- scripts/makefile.netbsd | 2 +- scripts/makefile.openbsd | 2 +- scripts/pnglibconf.dfa | 9 +- scripts/pnglibconf.h.prebuilt | 4 +- scripts/symbols.def | 2 +- 43 files changed, 1148 insertions(+), 235 deletions(-) create mode 100644 arm/filter_neon_intrinsics.c diff --git a/ANNOUNCE b/ANNOUNCE index f4d2fcebb..b29489ab5 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -1,5 +1,5 @@ -Libpng 1.6.5 - September 14, 2013 +Libpng 1.6.7 - November 14, 2013 This is a public release of libpng, intended for use in production codes. @@ -8,24 +8,81 @@ Files available for download: Source files with LF line endings (for Unix/Linux) and with a "configure" script - libpng-1.6.5.tar.xz (LZMA-compressed, recommended) - libpng-1.6.5.tar.gz + libpng-1.6.7.tar.xz (LZMA-compressed, recommended) + libpng-1.6.7.tar.gz Source files with CRLF line endings (for Windows), without the "configure" script - lpng165.7z (LZMA-compressed, recommended) - lpng165.zip + lpng167.7z (LZMA-compressed, recommended) + lpng167.zip Other information: - libpng-1.6.5-README.txt - libpng-1.6.5-LICENSE.txt + libpng-1.6.7-README.txt + libpng-1.6.7-LICENSE.txt Gnupg/*.asc (PGP armored detached signatures) -Changes since the last public release (1.6.4): +Changes since the last public release (1.6.6): - No changes. + Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE + combination + Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also + fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff + which terminates the make options (as by default in recent versions of + Gentoo). + Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of + png_modifier are greater than that of png_store and as a consequence + compilation of pngvalid.c results in a warning about increased alignment + requirements because of the bare cast to (png_modifier*). The code is safe, + because the pointer is known to point to a stack allocated png_modifier, + but this change avoids the warning. + Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was + compiled without the CHECK option it defaulted to on, not off. + Check user callback behavior in pngunknown.c. Previous versions compiled + if SAVE_UNKNOWN was not available but did nothing since the callback + was never implemented. + Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes + Made changes for compatibility with automake 1.14: + 1) Added the 'compile' program to the list of programs that must be cleaned + in autogen.sh + 2) Added 'subdir-objects' which causes .c files in sub-directories to be + compiled such that the corresponding .o files are also in the + sub-directory. This is because automake 1.14 warns that the + current behavior of compiling to the top level directory may be removed + in the future. + 3) Updated dependencies on pnglibconf.h to match the new .o locations and + added all the files in contrib/libtests and contrib/tools that depend + on pnglibconf.h + 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended + way of handling the dependencies of sources that are machine generated; + unfortunately it only works if the user does 'make all' or 'make check', + so the dependencies (3) are still required. + Cleaned up (char*) casts of zlib messages. The latest version of the Intel C + compiler complains about casting a string literal as (char*), so copied the + treatment of z_const from the library code into pngfix.c + Simplified error message code in pngunknown. The simplification has the + useful side effect of avoiding a bogus warning generated by the latest + version of the Intel C compiler (it objects to + condition ? string-literal : string-literal). + Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always + removing the 1.14 'compile' script but never checking for it. + Added ARMv8 support (James Yu ). Added file + arm/filter_neon_intrinsics.c; enable with -mfpu=neon. + Revised pngvalid to generate size images with as many filters as it can + manage, limited by the number of rows. + Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h + and detect the broken GCC compilers. + Allow clang derived from older GCC versions to use ARM intrinsics. This + causes all clang builds that use -mfpu=neon to use the intrinsics code, + not the assembler code. This has only been tested on iOS 7. It may be + necessary to exclude some earlier clang versions but this seems unlikely. + Changed NEON implementation selection mechanism. This allows assembler + or intrinsics to be turned on at compile time during the build by defining + PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro + is undefined by default and the build type is selected in pngpriv.h. + Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char + checking macros take an unsigned char argument, not a signed char. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 3ab18d574..953e53ab9 100644 --- a/CHANGES +++ b/CHANGES @@ -4637,6 +4637,82 @@ Version 1.6.4 [September 12, 2013] Version 1.6.5 [September 14, 2013] Removed two stray lines of code from arm/arm_init.c. +Version 1.6.6 [September 16, 2013] + Removed two stray lines of code from arm/arm_init.c, again. + +Version 1.6.7beta01 [September 30, 2013] + Revised unknown chunk code to correct several bugs in the NO_SAVE_/NO_WRITE + combination + Allow HANDLE_AS_UNKNOWN to work when other options are configured off. Also + fixed the pngminim makefiles to work when $(MAKEFLAGS) contains stuff + which terminates the make options (as by default in recent versions of + Gentoo). + Avoid up-cast warnings in pngvalid.c. On ARM the alignment requirements of + png_modifier are greater than that of png_store and as a consequence + compilation of pngvalid.c results in a warning about increased alignment + requirements because of the bare cast to (png_modifier*). The code is safe, + because the pointer is known to point to a stack allocated png_modifier, + but this change avoids the warning. + Fixed default behavior of ARM_NEON_API. If the ARM NEON API option was + compiled without the CHECK option it defaulted to on, not off. + Check user callback behavior in pngunknown.c. Previous versions compiled + if SAVE_UNKNOWN was not available but did nothing since the callback + was never implemented. + Merged pngunknown.c with 1.7 version and back ported 1.7 improvements/fixes + +Version 1.6.7beta02 [October 12, 2013] + Made changes for compatibility with automake 1.14: + 1) Added the 'compile' program to the list of programs that must be cleaned + in autogen.sh + 2) Added 'subdir-objects' which causes .c files in sub-directories to be + compiled such that the corresponding .o files are also in the + sub-directory. This is because automake 1.14 warns that the + current behavior of compiling to the top level directory may be removed + in the future. + 3) Updated dependencies on pnglibconf.h to match the new .o locations and + added all the files in contrib/libtests and contrib/tools that depend + on pnglibconf.h + 4) Added 'BUILD_SOURCES = pnglibconf.h'; this is the automake recommended + way of handling the dependencies of sources that are machine generated; + unfortunately it only works if the user does 'make all' or 'make check', + so the dependencies (3) are still required. + Cleaned up (char*) casts of zlib messages. The latest version of the Intel C + compiler complains about casting a string literal as (char*), so copied the + treatment of z_const from the library code into pngfix.c + Simplified error message code in pngunknown. The simplification has the + useful side effect of avoiding a bogus warning generated by the latest + version of the Intel C compiler (it objects to + condition ? string-literal : string-literal). + Make autogen.sh work with automake 1.13 as well as 1.14. Do this by always + removing the 1.14 'compile' script but never checking for it. + +Version 1.6.7beta03 [October 19, 2013] + Added ARMv8 support (James Yu ). Added file + arm/filter_neon_intrinsics.c; enable with -mfpu=neon. + Revised pngvalid to generate size images with as many filters as it can + manage, limited by the number of rows. + Cleaned up ARM NEON compilation handling. The tests are now in pngpriv.h + and detect the broken GCC compilers. + +Version 1.6.7beta04 [October 26, 2013] + Allow clang derived from older GCC versions to use ARM intrinsics. This + causes all clang builds that use -mfpu=neon to use the intrinsics code, + not the assembler code. This has only been tested on iOS 7. It may be + necessary to exclude some earlier clang versions but this seems unlikely. + Changed NEON implementation selection mechanism. This allows assembler + or intrinsics to be turned on at compile time during the build by defining + PNG_ARM_NEON_IMPLEMENTATION to the correct value (2 or 1). This macro + is undefined by default and the build type is selected in pngpriv.h. + +Version 1.6.7rc01 [November 2, 2013] + No changes. + +Version 1.6.7rc02 [November 7, 2013] + Fixed #include in filter_neon_intrinsics.c and ctype macros. The ctype char + checking macros take an unsigned char argument, not a signed char. + +Version 1.6.7rc03 [November 14, 2013] + Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit https://lists.sourceforge.net/lists/listinfo/png-mng-implement diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d9e98e40..4b4e74c07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ enable_testing() set(PNGLIB_MAJOR 1) set(PNGLIB_MINOR 6) -set(PNGLIB_RELEASE 5) +set(PNGLIB_RELEASE 7) set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) @@ -252,7 +252,7 @@ endif(NOT WIN32 OR CYGWIN OR MINGW) # SET UP LINKS if(PNG_SHARED) set_target_properties(${PNG_LIB_NAME} PROPERTIES -# VERSION 16.${PNGLIB_RELEASE}.1.6.5 +# VERSION 16.${PNGLIB_RELEASE}.1.6.7 VERSION 16.${PNGLIB_RELEASE}.0 SOVERSION 16 CLEAN_DIRECT_OUTPUT 1) diff --git a/LICENSE b/LICENSE index 170e89423..b1b97ea57 100644 --- a/LICENSE +++ b/LICENSE @@ -10,7 +10,7 @@ this sentence. This code is released under the libpng license. -libpng versions 1.2.6, August 15, 2004, through 1.6.5, September 14, 2013, are +libpng versions 1.2.6, August 15, 2004, through 1.6.7, November 14, 2013, are Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors @@ -108,4 +108,4 @@ certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net -September 14, 2013 +November 14, 2013 diff --git a/Makefile.am b/Makefile.am index 74a33e672..5ac0423e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,6 +12,16 @@ check_PROGRAMS= pngtest pngunknown pngstest pngvalid # Utilities - installed bin_PROGRAMS= pngfix png-fix-itxt +# This ensures that pnglibconf.h gets built at the start of 'make all' or +# 'make check', but it does not add dependencies to the individual programs, +# this is done below. +# +# IMPORTANT: always add the object modules of new programs to the list below +# because otherwise the sequence 'configure; make new-program' will *sometimes* +# result in the installed (system) pnglibconf.h being used and the result is +# always wrong and always very confusing. +BUILT_SOURCES = pnglibconf.h + pngtest_SOURCES = pngtest.c pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la @@ -71,8 +81,8 @@ libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES = png.c pngerror.c\ png.h pngconf.h pngdebug.h pnginfo.h pngpriv.h pngstruct.h pngusr.dfa if PNG_ARM_NEON -libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES += arm/arm_init.c\ - arm/filter_neon.S + libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES += arm/arm_init.c\ + arm/filter_neon.S arm/filter_neon_intrinsics.c endif nodist_libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@_la_SOURCES = pnglibconf.h @@ -194,9 +204,21 @@ $(srcdir)/scripts/pnglibconf.h.prebuilt: # The following is necessary to ensure that the local pnglibconf.h is used, not # an installed one (this can happen immediately after on a clean system if -# 'make test' is the first thing the user does.) -pngstest.o pngvalid.o pngtest.o pngunknown.o timepng.o: pnglibconf.h -pngfix.o png-fix-itxt.o: pnglibconf.h +# 'make test' is the first thing the user does.) Only files which include +# one of the png source files (typically png.h or pngpriv.h) need to be listed +# here: +pngtest.o: pnglibconf.h + +contrib/libtests/makepng.o: pnglibconf.h +contrib/libtests/pngstest.o: pnglibconf.h +contrib/libtests/pngunknown.o: pnglibconf.h +contrib/libtests/pngvalid.o: pnglibconf.h +contrib/libtests/readpng.o: pnglibconf.h +contrib/libtests/tarith.o: pnglibconf.h +contrib/libtests/timepng.o: pnglibconf.h + +contrib/tools/makesRGB.o: pnglibconf.h +contrib/tools/pngfix.o: pnglibconf.h # We must use -DPNG_NO_USE_READ_MACROS here even when the library may actually # be built with PNG_USE_READ_MACROS; this prevents the read macros from @@ -302,3 +324,8 @@ uninstall-hook: rm -f '$(DESTDIR)$(libdir)/libpng.sl' rm -f '$(DESTDIR)$(libdir)/libpng.dylib' rm -f '$(DESTDIR)$(libdir)/libpng.dll.a' + +# The following addition ensures that 'make all' always builds the test programs +# too. It used to, but some change either in libpng or configure stopped this +# working. +all-am: $(check_PROGRAMS) diff --git a/README b/README index 37cc9b313..80fc574ad 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -README for libpng version 1.6.5 - September 14, 2013 (shared library 16.0) +README for libpng version 1.6.7 - November 14, 2013 (shared library 16.0) See the note about version numbers near the top of png.h See INSTALL for instructions on how to install libpng. diff --git a/arm/arm_init.c b/arm/arm_init.c index d26b8843c..098771781 100644 --- a/arm/arm_init.c +++ b/arm/arm_init.c @@ -3,7 +3,7 @@ * * Copyright (c) 2013 Glenn Randers-Pehrson * Written by Mans Rullgard, 2011. - * Last changed in libpng 1.6.5 [September 14, 2013] + * Last changed in libpng 1.6.6 [September 16, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -17,8 +17,6 @@ #include "../pngpriv.h" #ifdef PNG_READ_SUPPORTED - if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == - PNG_OPTION_ON) #if PNG_ARM_NEON_OPT > 0 #ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */ #include /* for sig_atomic_t */ @@ -156,6 +154,16 @@ png_have_neon(png_structp png_ptr) void png_init_filter_functions_neon(png_structp pp, unsigned int bpp) { + /* The switch statement is compiled in for ARM_NEON_API, the call to + * png_have_neon is compiled in for ARM_NEON_CHECK. If both are defined + * the check is only performed if the API has not set the NEON option on + * or off explicitly. In this case the check controls what happens. + * + * If the CHECK is not compiled in and the option is UNSET the behavior prior + * to 1.6.7 was to use the NEON code - this was a bug caused by having the + * wrong order of the 'ON' and 'default' cases. UNSET now defaults to OFF, + * as documented in png.h + */ #ifdef PNG_ARM_NEON_API_SUPPORTED switch ((pp->options >> PNG_ARM_NEON) & 3) { @@ -180,13 +188,14 @@ png_init_filter_functions_neon(png_structp pp, unsigned int bpp) break; #endif #endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ + #ifdef PNG_ARM_NEON_API_SUPPORTED + default: /* OFF or INVALID */ + return; + case PNG_OPTION_ON: /* Option turned on */ break; - - default: /* OFF or INVALID */ - return; } #endif diff --git a/arm/filter_neon.S b/arm/filter_neon.S index b8aef1053..3d1ccf505 100644 --- a/arm/filter_neon.S +++ b/arm/filter_neon.S @@ -3,7 +3,7 @@ * * Copyright (c) 2013 Glenn Randers-Pehrson * Written by Mans Rullgard, 2011. - * Last changed in libpng 1.5.17 [July 18, 2013] + * Last changed in libpng 1.6.7 [November 14, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -20,6 +20,13 @@ .section .note.GNU-stack,"",%progbits /* mark stack as non-executable */ #endif +/* Assembler NEON support - only works for 32-bit ARM (i.e. it does not work for + * ARM64). The code in arm/filter_neon_intrinsics.c supports ARM64, however it + * only works if -mfpu=neon is specified on the GCC command line. See pngpriv.h + * for the logic which sets PNG_USE_ARM_NEON_ASM: + */ +#if PNG_ARM_NEON_IMPLEMENTATION == 2 /* hand-coded assembler */ + #ifdef PNG_READ_SUPPORTED #if PNG_ARM_NEON_OPT > 0 @@ -235,3 +242,4 @@ func png_read_filter_row_paeth3_neon, export=1 endfunc #endif /* PNG_ARM_NEON_OPT > 0 */ #endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_ARM_NEON_IMPLEMENTATION == 2 (assembler) */ diff --git a/arm/filter_neon_intrinsics.c b/arm/filter_neon_intrinsics.c new file mode 100644 index 000000000..e6a0217ab --- /dev/null +++ b/arm/filter_neon_intrinsics.c @@ -0,0 +1,372 @@ + +/* filter_neon_intrinsics.c - NEON optimised filter functions + * + * Copyright (c) 2013 Glenn Randers-Pehrson + * Written by James Yu , October 2013. + * Based on filter_neon.S, written by Mans Rullgard, 2011. + * + * Last changed in libpng 1.6.7 [November 14, 2013] + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "../pngpriv.h" + +/* This code requires -mfpu=neon on the command line: */ +#if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code */ + +#include + +/* libpng row pointers are not necessarily aligned to any particular boundary, + * however this code will only work with appropriate alignment. arm/arm_init.c + * checks for this (and will not compile unless it is done), this code uses + * variants of png_aligncast to avoid compiler warnings. + */ +#define png_ptr(type,pointer) png_aligncast(type *,pointer) +#define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer) + +/* The following relies on a variable 'temp_pointer' being declared with type + * 'type'. This is written this way just to hide the GCC strict aliasing + * warning; note that the code is safe because there never is an alias between + * the input and output pointers. + */ +#define png_ldr(type,pointer)\ + (temp_pointer = png_ptr(type,pointer), *temp_pointer) + +#ifdef PNG_READ_SUPPORTED +#if PNG_ARM_NEON_OPT > 0 + +void +png_read_filter_row_up_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint8x16_t qrp, qpp; + + qrp = vld1q_u8(rp); + qpp = vld1q_u8(pp); + qrp = vaddq_u8(qrp, qpp); + vst1q_u8(rp, qrp); + } +} + +void +png_read_filter_row_sub3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp = vld1q_u8(rp); + uint8x8x2_t *vrpt = png_ptr(uint8x8x2_t, &vtmp); + uint8x8x2_t vrp = *vrpt; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + for (; rp < rp_stop;) + { + uint8x8_t vtmp1, vtmp2; + uint32x2_t *temp_pointer; + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); + vtmp2 = vext_u8(vrp.val[0], vrp.val[1], 6); + vdest.val[1] = vadd_u8(vdest.val[0], vtmp1); + + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + vdest.val[2] = vadd_u8(vdest.val[1], vtmp2); + vdest.val[3] = vadd_u8(vdest.val[2], vtmp1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t, &vtmp); + vrp = *vrpt; + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } + + PNG_UNUSED(prev_row) +} + +void +png_read_filter_row_sub4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + for (; rp < rp_stop; rp += 16) + { + uint32x2x4_t vtmp = vld4_u32(png_ptr(uint32_t,rp)); + uint8x8x4_t *vrpt = png_ptr(uint8x8x4_t,&vtmp); + uint8x8x4_t vrp = *vrpt; + uint32x2x4_t *temp_pointer; + + vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[0], vrp.val[1]); + vdest.val[2] = vadd_u8(vdest.val[1], vrp.val[2]); + vdest.val[3] = vadd_u8(vdest.val[2], vrp.val[3]); + vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); + } + + PNG_UNUSED(prev_row) +} + +void +png_read_filter_row_avg3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_const_bytep pp = prev_row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp; + uint8x8x2_t *vrpt; + uint8x8x2_t vrp; + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + vtmp = vld1q_u8(rp); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + for (; rp < rp_stop; pp += 12) + { + uint8x8_t vtmp1, vtmp2, vtmp3; + + uint8x8x2_t *vppt; + uint8x8x2_t vpp; + + uint32x2_t *temp_pointer; + + vtmp = vld1q_u8(pp); + vppt = png_ptr(uint8x8x2_t,&vtmp); + vpp = *vppt; + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); + vtmp3 = vext_u8(vrp.val[0], vrp.val[1], 6); + vdest.val[1] = vhadd_u8(vdest.val[0], vtmp2); + vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); + + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 6); + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + vdest.val[2] = vhadd_u8(vdest.val[1], vtmp2); + vdest.val[2] = vadd_u8(vdest.val[2], vtmp3); + + vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); + + vdest.val[3] = vhadd_u8(vdest.val[2], vtmp2); + vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } +} + +void +png_read_filter_row_avg4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint32x2x4_t vtmp; + uint8x8x4_t *vrpt, *vppt; + uint8x8x4_t vrp, vpp; + uint32x2x4_t *temp_pointer; + + vtmp = vld4_u32(png_ptr(uint32_t,rp)); + vrpt = png_ptr(uint8x8x4_t,&vtmp); + vrp = *vrpt; + vtmp = vld4_u32(png_ptrc(uint32_t,pp)); + vppt = png_ptr(uint8x8x4_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + vdest.val[1] = vhadd_u8(vdest.val[0], vpp.val[1]); + vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); + vdest.val[2] = vhadd_u8(vdest.val[1], vpp.val[2]); + vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); + vdest.val[3] = vhadd_u8(vdest.val[2], vpp.val[3]); + vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); + + vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); + } +} + +static uint8x8_t +paeth(uint8x8_t a, uint8x8_t b, uint8x8_t c) +{ + uint8x8_t d, e; + uint16x8_t p1, pa, pb, pc; + + p1 = vaddl_u8(a, b); /* a + b */ + pc = vaddl_u8(c, c); /* c * 2 */ + pa = vabdl_u8(b, c); /* pa */ + pb = vabdl_u8(a, c); /* pb */ + pc = vabdq_u16(p1, pc); /* pc */ + + p1 = vcleq_u16(pa, pb); /* pa <= pb */ + pa = vcleq_u16(pa, pc); /* pa <= pc */ + pb = vcleq_u16(pb, pc); /* pb <= pc */ + + p1 = vandq_u16(p1, pa); /* pa <= pb && pa <= pc */ + + d = vmovn_u16(pb); + e = vmovn_u16(p1); + + d = vbsl_u8(d, b, c); + e = vbsl_u8(e, a, d); + + return e; +} + +void +png_read_filter_row_paeth3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_const_bytep pp = prev_row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp; + uint8x8x2_t *vrpt; + uint8x8x2_t vrp; + uint8x8_t vlast = vdup_n_u8(0); + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + vtmp = vld1q_u8(rp); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + for (; rp < rp_stop; pp += 12) + { + uint8x8x2_t *vppt; + uint8x8x2_t vpp; + uint8x8_t vtmp1, vtmp2, vtmp3; + uint32x2_t *temp_pointer; + + vtmp = vld1q_u8(pp); + vppt = png_ptr(uint8x8x2_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); + vdest.val[1] = paeth(vdest.val[0], vtmp2, vpp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6); + vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6); + vdest.val[2] = paeth(vdest.val[1], vtmp3, vtmp2); + vdest.val[2] = vadd_u8(vdest.val[2], vtmp1); + + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + vdest.val[3] = paeth(vdest.val[2], vtmp2, vtmp3); + vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); + + vlast = vtmp2; + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } +} + +void +png_read_filter_row_paeth4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + uint8x8_t vlast = vdup_n_u8(0); + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint32x2x4_t vtmp; + uint8x8x4_t *vrpt, *vppt; + uint8x8x4_t vrp, vpp; + uint32x2x4_t *temp_pointer; + + vtmp = vld4_u32(png_ptr(uint32_t,rp)); + vrpt = png_ptr(uint8x8x4_t,&vtmp); + vrp = *vrpt; + vtmp = vld4_u32(png_ptrc(uint32_t,pp)); + vppt = png_ptr(uint8x8x4_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + vdest.val[1] = paeth(vdest.val[0], vpp.val[1], vpp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); + vdest.val[2] = paeth(vdest.val[1], vpp.val[2], vpp.val[1]); + vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); + vdest.val[3] = paeth(vdest.val[2], vpp.val[3], vpp.val[2]); + vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); + + vlast = vpp.val[3]; + + vst4_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2x4_t,&vdest), 0); + } +} + +#endif /* PNG_ARM_NEON_OPT > 0 */ +#endif /* PNG_READ_SUPPORTED */ +#endif /* PNG_ARM_NEON_IMPLEMENTATION == 1 (intrinsics) */ diff --git a/autogen.sh b/autogen.sh index decf0f56f..9af34bde2 100755 --- a/autogen.sh +++ b/autogen.sh @@ -9,15 +9,15 @@ # # For regular ("tarball") distributions all the files should exist. We do not # want them to be updated *under any circumstances*. It should never be -# necessary to rune autogen.sh because ./configure --enable-maintainer-mode says -# what to do if Makeile.am or configure.ac are changed. +# necessary to run autogen.sh because ./configure --enable-maintainer-mode says +# what to do if Makefile.am or configure.ac are changed. # # It is *probably* OK to update the files on a GIT checkout, because they have # come from the local tools, but leave that to the user who is assumed to know # whether it is ok or required. # # This script is intended to work without arguments, there are, however, hidden -# arguments for (a) use while testing the script and (b) to fix up systems that +# arguments (a) for use while testing the script and (b) to fix up systems that # have been broken. If (b) is required the script prompts for the correct # options. For this reason the options are *NOT* documented in the help; this # is deliberate; UTSL. @@ -76,6 +76,10 @@ done libpng_autotools_files="Makefile.in aclocal.m4 config.guess config.h.in\ config.sub configure depcomp install-sh ltmain.sh missing test-driver" # +# Files generated by versions of configue >2.68 or automake >1.13 (i.e. later +# versions than those required by configure.ac): +libpng_autotools_extra="compile" +# # These are separate because 'maintainer-clean' does not remove them. libpng_libtool_files="scripts/libtool.m4 scripts/ltoptions.m4\ scripts/ltsugar.m4 scripts/ltversion.m4 scripts/lt~obsolete.m4" @@ -94,6 +98,7 @@ libpng_configure_dirs=".deps" # of Makefile. These functions do the two bits of cleaning. clean_autotools(){ rm -rf $libpng_autotools_files $libpng_libtool_files $libpng_autotools_dirs + rm -rf $libpng_autotools_extra } clean_configure(){ @@ -198,7 +203,7 @@ case "$mode" in echo " You can run autoreconf yourself if you don't like maintainer" echo " mode and you can also just run autoreconf -f -i to initialize" echo " everything in the first place; this script is only for" - echo " compatiblity with prior releases." + echo " compatibility with prior releases." exit 1 else exec >&2 diff --git a/configure.ac b/configure.ac index aaa298f86..28200c3f6 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ AC_PREREQ([2.68]) dnl Version number stuff here: -AC_INIT([libpng],[1.6.5],[png-mng-implement@lists.sourceforge.net]) +AC_INIT([libpng],[1.6.7],[png-mng-implement@lists.sourceforge.net]) AC_CONFIG_MACRO_DIR([scripts]) # libpng does not follow GNU file name conventions (hence 'foreign') @@ -27,7 +27,7 @@ AC_CONFIG_MACRO_DIR([scripts]) # dist-xz requires automake 1.11 or later # 1.12.2 fixes a security issue in 1.11.2 and 1.12.1 # 1.13 is required for parallel tests -AM_INIT_AUTOMAKE([1.13 foreign dist-xz color-tests silent-rules]) +AM_INIT_AUTOMAKE([1.13 foreign dist-xz color-tests silent-rules subdir-objects]) # The following line causes --disable-maintainer-mode to be the default to # configure, this is necessary because libpng distributions cannot rely on the # time stamps of the autotools generated files being correct @@ -39,10 +39,10 @@ dnl automake, so the following is not necessary (and is not defined anyway): dnl AM_PREREQ([1.11.2]) dnl stop configure from automagically running automake -PNGLIB_VERSION=1.6.5 +PNGLIB_VERSION=1.6.7 PNGLIB_MAJOR=1 PNGLIB_MINOR=6 -PNGLIB_RELEASE=5 +PNGLIB_RELEASE=7 dnl End of version number stuff diff --git a/contrib/libtests/pngunknown.c b/contrib/libtests/pngunknown.c index 25452dbc9..a21c9d75d 100644 --- a/contrib/libtests/pngunknown.c +++ b/contrib/libtests/pngunknown.c @@ -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 @@ typedef png_byte *png_const_bytep; # 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(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 @@ static struct { "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 @@ find_by_flag(png_uint_32 flag) 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 @@ typedef struct 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 @@ clean_display(display *d) d->test); exit(1); } - - /* Invalidate the test */ - d->test = init; } PNG_FUNCTION(void, display_exit, (display *d), static PNG_NORETURN) @@ -444,11 +489,88 @@ get_valid(display *d, png_infop info_ptr) return flags; } +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED +static int +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 @@ get_unknown(display *d, int def, png_infop info_ptr) 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 @@ get_unknown(display *d, int def, png_infop info_ptr) 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 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, 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 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, * 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 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, 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 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, 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 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/, 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 @@ check_error(display *d, png_uint_32 flags, const char *message) 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 @@ check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, 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 @@ check_handling(display *d, int def, png_uint_32 chunks, png_uint_32 known, 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 @@ perform_one_test(FILE *fp, int argc, const char **argv, 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 @@ perform_one_test(FILE *fp, int argc, const char **argv, * 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 @@ perform_one_test_safe(FILE *fp, int argc, const char **argv, 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 @@ usage(const char *program, const char *reason) 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 @@ main(int argc, const char **argv) 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 @@ main(int argc, const char **argv) 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 @@ main(int argc, const char **argv) 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 @@ main(int argc, const char **argv) 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*/ diff --git a/contrib/libtests/pngvalid.c b/contrib/libtests/pngvalid.c index fbd6778cf..55ec5af4f 100644 --- a/contrib/libtests/pngvalid.c +++ b/contrib/libtests/pngvalid.c @@ -616,7 +616,12 @@ typedef struct png_store unsigned int validated :1; /* used as a temporary flag */ int nerrors; int nwarnings; - char test[128]; /* Name of test */ + int noptions; /* number of options below: */ + struct { + unsigned char option; /* option number, 0..30 */ + unsigned char setting; /* setting (unset,invalid,on,off) */ + } options[16]; + char test[128]; /* Name of test */ char error[256]; /* Read fields */ @@ -717,6 +722,7 @@ store_init(png_store* ps) ps->new.prev = NULL; ps->palette = NULL; ps->npalette = 0; + ps->noptions = 0; } static void @@ -1518,6 +1524,16 @@ set_store_for_write(png_store *ps, png_infopp ppi, png_set_write_fn(ps->pwrite, ps, store_write, store_flush); +# ifdef PNG_SET_OPTION_SUPPORTED + { + int opt; + for (opt=0; optnoptions; ++opt) + if (png_set_option(ps->pwrite, ps->options[opt].option, + ps->options[opt].setting) == PNG_OPTION_INVALID) + png_error(ps->pwrite, "png option invalid"); + } +# endif + if (ppi != NULL) *ppi = ps->piwrite = png_create_info_struct(ps->pwrite); } @@ -1581,14 +1597,14 @@ store_read_set(png_store *ps, png_uint_32 id) pf = pf->next; } - { + { size_t pos; char msg[FILE_NAME_SIZE+64]; pos = standard_name_from_id(msg, sizeof msg, 0, id); pos = safecat(msg, sizeof msg, pos, ": file not found"); png_error(ps->pread, msg); - } + } } /* The main interface for reading a saved file - pass the id number of the file @@ -1633,6 +1649,16 @@ set_store_for_read(png_store *ps, png_infopp ppi, png_uint_32 id, Throw ps; } +# ifdef PNG_SET_OPTION_SUPPORTED + { + int opt; + for (opt=0; optnoptions; ++opt) + if (png_set_option(ps->pread, ps->options[opt].option, + ps->options[opt].setting) == PNG_OPTION_INVALID) + png_error(ps->pread, "png option invalid"); + } +# endif + store_read_set(ps, id); if (ppi != NULL) @@ -2919,6 +2945,12 @@ sbit_modification_init(sbit_modification *me, png_modifier *pm, png_byte sbit) * height of 16 rows. The width and height are stored in the FILEID and, being * non-zero, indicate a size file. * + * Because the PNG filter code is typically the largest CPU consumer within + * libpng itself there is a tendency to attempt to optimize it. This results in + * special case code which needs to be validated. To cause this to happen the + * 'size' images are made to use each possible filter, in so far as this is + * possible for smaller images. + * * For palette image (colour type 3) multiple transform images are stored with * the same bit depth to allow testing of more colour combinations - * particularly important for testing the gamma code because libpng uses a @@ -3634,6 +3666,7 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, int npasses = npasses_from_interlace_type(pp, interlace_type); png_uint_32 y; int pass; + int nfilter = PNG_FILTER_VALUE_LAST; png_byte image[16][SIZE_ROWMAX]; /* To help consistent error detection make the parts of this buffer @@ -3687,7 +3720,22 @@ make_size_image(png_store* PNG_CONST ps, png_byte PNG_CONST colour_type, continue; } - /* Only get to here if the row has some pixels in it. */ + /* Only get to here if the row has some pixels in it, set the + * filters to 'all' for the very first row and thereafter to a + * single filter. It isn't well documented, but png_set_filter + * does accept a filter number (per the spec) as well as a bit + * mask. + * + * The apparent wackiness of decrementing nfilter rather than + * incrementing is so that Paeth gets used in all images bigger + * than 1 row - it's the tricky one. + */ + png_set_filter(pp, 0/*method*/, + nfilter >= PNG_FILTER_VALUE_LAST ? PNG_ALL_FILTERS : nfilter); + + if (nfilter-- == 0) + nfilter = PNG_FILTER_VALUE_LAST-1; + png_write_row(pp, row); } } @@ -5988,7 +6036,7 @@ transform_test(png_modifier *pmIn, PNG_CONST png_uint_32 idIn, Catch(fault) { - modifier_reset((png_modifier*)fault); + modifier_reset(voidcast(png_modifier*,(void*)fault)); } } @@ -7122,7 +7170,7 @@ transform_enable(PNG_CONST char *name) { fprintf(stderr, "pngvalid: --transform-enable=%s: unknown transform\n", name); - exit(1); + exit(99); } } @@ -7144,7 +7192,7 @@ transform_disable(PNG_CONST char *name) fprintf(stderr, "pngvalid: --transform-disable=%s: unknown transform\n", name); - exit(1); + exit(99); } static void @@ -8692,7 +8740,7 @@ gamma_test(png_modifier *pmIn, PNG_CONST png_byte colour_typeIn, } Catch(fault) - modifier_reset((png_modifier*)fault); + modifier_reset(voidcast(png_modifier*,(void*)fault)); } static void gamma_threshold_test(png_modifier *pm, png_byte colour_type, @@ -9448,7 +9496,7 @@ perform_interlace_macro_validation(void) if (m != f) { fprintf(stderr, "PNG_PASS_START_ROW(%d) = %u != %x\n", pass, m, f); - exit(1); + exit(99); } m = PNG_PASS_START_COL(pass); @@ -9456,7 +9504,7 @@ perform_interlace_macro_validation(void) if (m != f) { fprintf(stderr, "PNG_PASS_START_COL(%d) = %u != %x\n", pass, m, f); - exit(1); + exit(99); } m = PNG_PASS_ROW_SHIFT(pass); @@ -9464,7 +9512,7 @@ perform_interlace_macro_validation(void) if (m != f) { fprintf(stderr, "PNG_PASS_ROW_SHIFT(%d) = %u != %x\n", pass, m, f); - exit(1); + exit(99); } m = PNG_PASS_COL_SHIFT(pass); @@ -9472,7 +9520,7 @@ perform_interlace_macro_validation(void) if (m != f) { fprintf(stderr, "PNG_PASS_COL_SHIFT(%d) = %u != %x\n", pass, m, f); - exit(1); + exit(99); } /* Macros that depend on the image or sub-image height too: @@ -9493,7 +9541,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_ROW_FROM_PASS_ROW(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } m = PNG_COL_FROM_PASS_COL(v, pass); @@ -9502,7 +9550,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_COL_FROM_PASS_COL(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } m = PNG_ROW_IN_INTERLACE_PASS(v, pass); @@ -9511,7 +9559,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_ROW_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } m = PNG_COL_IN_INTERLACE_PASS(v, pass); @@ -9520,7 +9568,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_COL_IN_INTERLACE_PASS(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } /* Then the base 1 stuff: */ @@ -9531,7 +9579,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_PASS_ROWS(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } m = PNG_PASS_COLS(v, pass); @@ -9540,7 +9588,7 @@ perform_interlace_macro_validation(void) { fprintf(stderr, "PNG_PASS_COLS(%u, %d) = %u != %x\n", v, pass, m, f); - exit(1); + exit(99); } /* Move to the next v - the stepping algorithm starts skipping @@ -9944,7 +9992,7 @@ int main(int argc, char **argv) else { fprintf(stderr, "pngvalid: %s: unknown 'max' option\n", *argv); - exit(1); + exit(99); } catmore = 1; @@ -9956,10 +10004,51 @@ int main(int argc, char **argv) else if (strcmp(*argv, "--log16") == 0) --argc, pm.log16 = atof(*++argv), catmore = 1; +#ifdef PNG_SET_OPTION_SUPPORTED + else if (strncmp(*argv, "--option=", 9) == 0) + { + /* Syntax of the argument is