diff --git a/ANNOUNCE b/ANNOUNCE index b5ee27256..d77c6bc6d 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -450,6 +450,14 @@ Version 1.6.0beta28 [August 16, 2012] There is a new test program, test-unknown.c, which is a work in progress (not currently part of the test suite). Comments in the header files now explain how the unknown handling works. + Allow fine grain control of unknown chunk APIs. This change allows + png_set_keep_unknown_chunks() to be turned off if not required and causes + both read and write to behave appropriately (on read this is only possible + if the user callback is used to handle unknown chunks). The change + also removes the support for storing unknown chunks in the info_struct + if the only unknown handling enabled is via the callback, allowing libpng + to be configured with callback reading and none of the unnecessary code. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index fab5c9dd2..9d9441853 100644 --- a/CHANGES +++ b/CHANGES @@ -4201,6 +4201,13 @@ Version 1.6.0beta28 [August 16, 2012] There is a new test program, test-unknown.c, which is a work in progress (not currently part of the test suite). Comments in the header files now explain how the unknown handling works. + Allow fine grain control of unknown chunk APIs. This change allows + png_set_keep_unknown_chunks() to be turned off if not required and causes + both read and write to behave appropriately (on read this is only possible + if the user callback is used to handle unknown chunks). The change + also removes the support for storing unknown chunks in the info_struct + if the only unknown handling enabled is via the callback, allowing libpng + to be configured with callback reading and none of the unnecessary code. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pngrutil.c b/pngrutil.c index 3982c80a7..88758deeb 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -2814,7 +2814,9 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, * function. */ # ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif # endif /* One of the following methods will read the chunk or skip it (at least one diff --git a/pngset.c b/pngset.c index 7cd23ff39..7defe7749 100644 --- a/pngset.c +++ b/pngset.c @@ -1111,6 +1111,29 @@ png_set_unknown_chunks(png_const_structrp png_ptr, if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0) return; + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !(defined PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + (defined PNG_READ_SUPPORTED) + if (png_ptr->mode & PNG_IS_READ_STRUCT) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + return; + } +# endif +# if !(defined PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + (defined PNG_WRITE_SUPPORTED) + if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + return; + } +# endif + /* Prior to 1.6.0 this code used png_malloc_warn, however this meant that * unknown critical chunks could be lost with just a warning resulting in * undefined behavior. Changing to png_malloc fixes this by producing a diff --git a/pngtest.c b/pngtest.c index 854c79616..0c7396166 100644 --- a/pngtest.c +++ b/pngtest.c @@ -567,12 +567,14 @@ png_debug_free(png_structp png_ptr, png_voidp ptr) /* Demonstration of user chunk support of the sTER and vpAg chunks */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED /* (sTER is a public chunk not yet known by libpng. vpAg is a private chunk used in ImageMagick to store "virtual page" size). */ -static png_uint_32 user_chunk_data[4]; +/* The initializer must match the values actually stored in pngtest.png so that + * pngtest will pass if we don't have read callback support. + */ +static png_uint_32 user_chunk_data[4] = {2, 'd', 'd', 0}; /* 0: sTER mode + 1 * 1: vpAg width @@ -580,6 +582,7 @@ static png_uint_32 user_chunk_data[4]; * 3: vpAg units */ +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) { @@ -726,7 +729,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) pngtest_warning); #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED user_chunk_data[0] = 0; user_chunk_data[1] = 0; user_chunk_data[2] = 0; @@ -862,6 +865,9 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) png_set_write_user_transform_fn(write_ptr, count_zero_samples); #endif +#if 0 /* the following code is pointless, it doesn't work unless + PNG_READ_USER_CHUNKS_SUPPORTED, in which case it does nothing. */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED # ifndef PNG_HANDLE_CHUNK_ALWAYS # define PNG_HANDLE_CHUNK_ALWAYS 3 @@ -875,6 +881,8 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) # endif png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, NULL, 0); +#endif +#endif #endif pngtest_debug("Reading info struct"); @@ -1163,7 +1171,6 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) */ png_write_info(write_ptr, write_info_ptr); -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED if (user_chunk_data[0] != 0) { png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; @@ -1199,7 +1206,6 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) } #endif -#endif #ifdef SINGLE_ROWBUF_ALLOC pngtest_debug("Allocating row buffer..."); diff --git a/pngwrite.c b/pngwrite.c index 6674af6d7..c0b65d120 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -35,6 +35,10 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, ++up) if (up->location & where) { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int keep = png_handle_as_unknown(png_ptr, up->name); /* NOTE: this code is radically different from the read side in the @@ -54,6 +58,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, keep == PNG_HANDLE_CHUNK_ALWAYS || (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif { /* TODO: review, what is wrong with a zero length unknown chunk? */ if (up->size == 0) @@ -872,7 +877,7 @@ png_write_destroy(png_structrp png_ptr) png_free(png_ptr, png_ptr->inv_filter_costs); #endif -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); #endif diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index 260dcf128..b5b1fca67 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -647,13 +647,13 @@ option UNKNOWN_CHUNKS # set by png_set_unknown_chunks will be written otherwise it is an error to call # that API on a write struct. option WRITE_UNKNOWN_CHUNKS requires WRITE requires UNKNOWN_CHUNKS -option WRITE_UNKNOWN_CHUNKS enables STORE_UNKNOWN_CHUNKS SET_UNKNOWN_CHUNKS +option WRITE_UNKNOWN_CHUNKS enables STORE_UNKNOWN_CHUNKS # The first way to read user chunks is to have libpng save them for a later call # to png_get_unknown_chunks, the application must call # png_set_keep_unknown_chunks to cause this to actually happen (see png.h) -option SAVE_UNKNOWN_CHUNKS requires READ requires UNKNOWN_CHUNKS -option SAVE_UNKNOWN_CHUNKS enables READ_UNKNOWN_CHUNKS +option SAVE_UNKNOWN_CHUNKS requires READ requires SET_UNKNOWN_CHUNKS +option SAVE_UNKNOWN_CHUNKS enables READ_UNKNOWN_CHUNKS STORE_UNKNOWN_CHUNKS # The second approach is to use an application provided callback to process the # chunks, the callback can either handle the chunk entirely itself or request @@ -664,23 +664,26 @@ option SAVE_UNKNOWN_CHUNKS enables READ_UNKNOWN_CHUNKS option READ_USER_CHUNKS requires READ requires UNKNOWN_CHUNKS option READ_USER_CHUNKS enables READ_UNKNOWN_CHUNKS USER_CHUNKS -# A further option allows known chunks to be handled using the unknown code by -# providing the relevant chunks to png_set_keep_unknown_chunks. This is turned -# on by the following option. In 1.6.0 turning this option *off* no longer -# disables png_set_keep_unknown_chunks, a behavior which effectively prevented -# unknown chunk saving by the first mechanism on read. +# Two further options are provided to allow detailed control of the handling. +# The first enables png_set_keep_unknown_chunks; this allows the default to be +# changed from discarding unknown chunks and allows per-chunk control. This is +# required to use the SAVE_UNKNOWN_CHUNKS option. If enabled this option also +# applies to write (see png.h), otherwise the write API simply writes all the +# chunks it is given. # -# Notice that this option no longer affects the write code either. It can be -# safely disabled and will prevent applications stopping libpng reading known -# chunks. +# The second option extends the unknown handling to allow known chunks to be +# handled as though they were unknown. This option doesn't change any APIs, it +# merely turns on the code to check known as well as unknown chunks. +# +# This option no longer affects the write code. It can be safely disabled and +# will prevent applications stopping libpng reading known chunks. +option SET_UNKNOWN_CHUNKS requires UNKNOWN_CHUNKS option HANDLE_AS_UNKNOWN requires SET_UNKNOWN_CHUNKS # The following options are derived from the above and should not be turned on # explicitly. option READ_UNKNOWN_CHUNKS requires UNKNOWN_CHUNKS disabled -option READ_UNKNOWN_CHUNKS enables STORE_UNKNOWN_CHUNKS SET_UNKNOWN_CHUNKS option STORE_UNKNOWN_CHUNKS requires UNKNOWN_CHUNKS disabled -option SET_UNKNOWN_CHUNKS requires UNKNOWN_CHUNKS disabled option CONVERT_tIME requires WRITE_ANCILLARY_CHUNKS # The "tm" structure is not supported on WindowsCE