diff --git a/png.c b/png.c index 9ab0ced40..fb4571ccb 100644 --- a/png.c +++ b/png.c @@ -866,58 +866,58 @@ png_access_version_number(void) * like Z_OK or Z_STREAM_END where the error code is apparently a success code. */ void /* PRIVATE */ -png_zstream_error(png_structrp png_ptr, int ret) +png_zstream_error(z_stream *zstream, int ret) { /* Translate 'ret' into an appropriate error string, priority is given to the * one in zstream if set. This always returns a string, even in cases like * Z_OK or Z_STREAM_END where the error code is a success code. */ - if (png_ptr->zstream.msg == NULL) switch (ret) + if (zstream->msg == NULL) switch (ret) { default: case Z_OK: - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); + zstream->msg = PNGZ_MSG_CAST("unexpected zlib return code"); break; case Z_STREAM_END: /* Normal exit */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); + zstream->msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); break; case Z_NEED_DICT: /* This means the deflate stream did not have a dictionary; this * indicates a bogus PNG. */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); + zstream->msg = PNGZ_MSG_CAST("missing LZ dictionary"); break; case Z_ERRNO: /* gz APIs only: should not happen */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); + zstream->msg = PNGZ_MSG_CAST("zlib IO error"); break; case Z_STREAM_ERROR: /* internal libpng error */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); + zstream->msg = PNGZ_MSG_CAST("bad parameters to zlib"); break; case Z_DATA_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); + zstream->msg = PNGZ_MSG_CAST("damaged LZ stream"); break; case Z_MEM_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); + zstream->msg = PNGZ_MSG_CAST("insufficient memory"); break; case Z_BUF_ERROR: /* End of input or output; not a problem if the caller is doing * incremental read or write. */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); + zstream->msg = PNGZ_MSG_CAST("truncated"); break; case Z_VERSION_ERROR: - png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); + zstream->msg = PNGZ_MSG_CAST("unsupported zlib version"); break; case PNG_UNEXPECTED_ZLIB_RETURN: @@ -926,7 +926,7 @@ png_zstream_error(png_structrp png_ptr, int ret) * and change pngpriv.h. Note that this message is "... return", * whereas the default/Z_OK one is "... return code". */ - png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); + zstream->msg = PNGZ_MSG_CAST("unexpected zlib return"); break; } } diff --git a/pngpriv.h b/pngpriv.h index f7adfa6fe..f990a9ab7 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -953,7 +953,7 @@ PNG_INTERNAL_FUNCTION(void, png_copy_row,(png_const_structrp png_ptr, /* Zlib support */ #define PNG_UNEXPECTED_ZLIB_RETURN (-7) -PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(z_stream *zstream, int ret), PNG_EMPTY); /* Used by the zlib handling functions to ensure that z_stream::msg is always * set before they return. @@ -1098,10 +1098,6 @@ PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, png_const_colorp palette, unsigned int num_pal),PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, - png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), - PNG_EMPTY); - PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_WRITE_gAMA_SUPPORTED @@ -1215,7 +1211,7 @@ PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, */ PNG_INTERNAL_FUNCTION(unsigned int, png_write_filter_row, (png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, - png_uint_32 x, png_uint_32 width/*pixels*/, int first_row_in_pass, + png_uint_32 x, unsigned int width/*pixels*/, int first_row_in_pass, int last_pass_row, unsigned int filters_to_try/*from previous call*/, int end_of_image), PNG_EMPTY); diff --git a/pngread.c b/pngread.c index acf013d4a..0aa7caa3b 100644 --- a/pngread.c +++ b/pngread.c @@ -751,7 +751,7 @@ png_read_destroy(png_structrp png_ptr) if (ret != Z_OK) { - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); png_warning(png_ptr, png_ptr->zstream.msg); } } diff --git a/pngrutil.c b/pngrutil.c index 425f3797a..c3b9e0e9a 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -362,7 +362,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) else { - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); png_ptr->zstream_ended = 1; } @@ -493,7 +493,7 @@ png_zlib_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, if (ret != Z_BUF_ERROR) png_ptr->zstream_ended = 1; - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); return ret; } @@ -667,14 +667,14 @@ png_decompress_chunk(png_structrp png_ptr, { /* Out of memory allocating the buffer */ ret = Z_MEM_ERROR; - png_zstream_error(png_ptr, Z_MEM_ERROR); + png_zstream_error(&png_ptr->zstream, Z_MEM_ERROR); } } else { /* inflateReset failed, store the error message */ - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); if (ret == Z_STREAM_END) ret = PNG_UNEXPECTED_ZLIB_RETURN; @@ -697,7 +697,7 @@ png_decompress_chunk(png_structrp png_ptr, else { /* Application/configuration limits exceeded */ - png_zstream_error(png_ptr, Z_MEM_ERROR); + png_zstream_error(&png_ptr->zstream, Z_MEM_ERROR); return Z_MEM_ERROR; } } @@ -758,7 +758,7 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ /* Ensure the error message pointer is always set: */ - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); return ret; } @@ -4513,7 +4513,7 @@ png_read_finish_IDAT(png_structrp png_ptr) /* This is just a warning; it's safe, and the zstream_error flag is * not set. */ - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); png_chunk_warning(png_ptr, png_ptr->zstream.msg); } } diff --git a/pngstruct.h b/pngstruct.h index a562c75f0..40009176d 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -64,14 +64,7 @@ #ifdef PNG_WRITE_SUPPORTED /* The type of a compression buffer list used by the write code. */ -typedef struct png_compression_buffer -{ - struct png_compression_buffer *next; - png_byte output[1]; /* actually zbuf_size */ -} png_compression_buffer, *png_compression_bufferp; - -#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ - (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +typedef struct png_compression_buffer *png_compression_bufferp; #endif /* Colorspace support; structures used in png_struct, png_info and in internal @@ -755,6 +748,7 @@ struct png_struct_def */ png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ z_stream zstream; /* decompression structure */ + unsigned int zstream_start:1; /* before first byte of stream */ unsigned int zstream_ended:1; /* no more zlib output available */ unsigned int zstream_error:1; /* zlib error message has been output */ unsigned int zstream_eod :1; /* all the required uncompressed data has been diff --git a/pngwrite.c b/pngwrite.c index afa065ce3..3f8371dc0 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1093,40 +1093,6 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) } /* png_ptr != NULL */ } -#ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set the automatic flush interval or 0 to turn flushing off */ -void PNGAPI -png_set_flush(png_structrp png_ptr, int nrows) -{ - png_debug(1, "in png_set_flush"); - - if (png_ptr == NULL) - return; - - png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); -} - -/* Flush the current output buffers now */ -void PNGAPI -png_write_flush(png_structrp png_ptr) -{ - png_debug(1, "in png_write_flush"); - - if (png_ptr == NULL) - return; - - /* Before the start of the IDAT and after the end of the image zowner will be - * something other than png_IDAT: - */ - if (png_ptr->zowner == png_IDAT) - { - png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); - png_ptr->flush_rows = 0; - png_flush(png_ptr); - } -} -#endif /* WRITE_FLUSH */ - /* Free any memory used in png_ptr struct without freeing the struct itself. */ static void png_write_destroy(png_structrp png_ptr) @@ -1140,7 +1106,7 @@ png_write_destroy(png_structrp png_ptr) if (ret != Z_OK) { - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); png_warning(png_ptr, png_ptr->zstream.msg); } } diff --git a/pngwutil.c b/pngwutil.c index 9d7c64fa9..7a051dbb7 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -203,7 +203,7 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, * point at which a lower LZ window size can be used.) */ static png_alloc_size_t -png_image_size(png_structrp png_ptr) +png_image_size(png_const_structrp png_ptr) { /* Only return sizes up to the maximum of a png_uint_32; do this by limiting * the width and height used to 15 bits. @@ -242,6 +242,16 @@ png_image_size(png_structrp png_ptr) return 0xffffffffU; } +/* The type of the compression buffer list (opaque outside this file) */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) + #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* This is the code to hack the first two bytes of the deflate stream (the * deflate header) to correct the windowBits value to match the actual data @@ -407,7 +417,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, if (ret_end != Z_OK || png_ptr->zstream.state != NULL) { - png_zstream_error(png_ptr, ret_end); + png_zstream_error(&png_ptr->zstream, ret_end); png_warning(png_ptr, png_ptr->zstream.msg); png_ptr->zstream.state = NULL; /* zlib error recovery */ } @@ -438,7 +448,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, png_ptr->zowner = owner; else - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); return ret; } @@ -616,7 +626,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, } else - png_zstream_error(png_ptr, ret); + png_zstream_error(&png_ptr->zstream, ret); /* Reset zlib for another zTXt/iTXt or image data */ png_ptr->zowner = 0; @@ -967,162 +977,6 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_ptr->mode |= PNG_HAVE_PLTE; } -/* This is similar to png_text_compress, above, except that it does not require - * all of the data at once and, instead of buffering the compressed result, - * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out - * because it calls the write interface. As a result it does its own error - * reporting and does not return an error code. In the event of error it will - * just call png_error. The input data length may exceed 32-bits. The 'flush' - * parameter is exactly the same as that to deflate, with the following - * meanings: - * - * Z_NO_FLUSH: normal incremental output of compressed data - * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush - * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up - * - * The routine manages the acquire and release of the png_ptr->zstream by - * checking and (at the end) clearing png_ptr->zowner; it does some sanity - * checks on the 'mode' flags while doing this. - */ -void /* PRIVATE */ -png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, - png_alloc_size_t input_len, int flush) -{ - if (png_ptr->zowner != png_IDAT) - { - /* First time. Ensure we have a temporary buffer for compression and - * trim the buffer list if it has more than one entry to free memory. - * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been - * created at this point, but the check here is quick and safe. - */ - if (png_ptr->zbuffer_list == NULL) - { - png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, - png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); - png_ptr->zbuffer_list->next = NULL; - } - - else - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); - - /* It is a terminal error if we can't claim the zstream. */ - if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg); - - /* The output state is maintained in png_ptr->zstream, so it must be - * initialized here after the claim. - */ - png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; - png_ptr->zstream.avail_out = png_ptr->zbuffer_size; - } - - /* Now loop reading and writing until all the input is consumed or an error - * terminates the operation. The _out values are maintained across calls to - * this function, but the input must be reset each time. - */ - png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); - png_ptr->zstream.avail_in = 0; /* set below */ - for (;;) - { - int ret; - - /* INPUT: from the row data */ - uInt avail = ZLIB_IO_MAX; - - if (avail > input_len) - avail = (uInt)input_len; /* safe because of the check */ - - png_ptr->zstream.avail_in = avail; - input_len -= avail; - - ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); - - /* Include as-yet unconsumed input */ - input_len += png_ptr->zstream.avail_in; - png_ptr->zstream.avail_in = 0; - - /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note - * that these two zstream fields are preserved across the calls, therefore - * there is no need to set these up on entry to the loop. - */ - if (png_ptr->zstream.avail_out == 0) - { - png_bytep data = png_ptr->zbuffer_list->output; - uInt size = png_ptr->zbuffer_size; - - /* Write an IDAT containing the data then reset the buffer. The - * first IDAT may need deflate header optimization. - */ -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - optimize_cmf(data, png_image_size(png_ptr)); -#endif - - png_write_complete_chunk(png_ptr, png_IDAT, data, size); - png_ptr->mode |= PNG_HAVE_IDAT; - - png_ptr->zstream.next_out = data; - png_ptr->zstream.avail_out = size; - - /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with - * the same flush parameter until it has finished output, for NO_FLUSH - * it doesn't matter. - */ - if (ret == Z_OK && flush != Z_NO_FLUSH) - continue; - } - - /* The order of these checks doesn't matter much; it just affects which - * possible error might be detected if multiple things go wrong at once. - */ - if (ret == Z_OK) /* most likely return code! */ - { - /* If all the input has been consumed then just return. If Z_FINISH - * was used as the flush parameter something has gone wrong if we get - * here. - */ - if (input_len == 0) - { - if (flush == Z_FINISH) - png_error(png_ptr, "Z_OK on Z_FINISH with output space"); - - return; - } - } - - else if (ret == Z_STREAM_END && flush == Z_FINISH) - { - /* This is the end of the IDAT data; any pending output must be - * flushed. For small PNG files we may still be at the beginning. - */ - png_bytep data = png_ptr->zbuffer_list->output; - uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; - -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - optimize_cmf(data, png_image_size(png_ptr)); -#endif - - png_write_complete_chunk(png_ptr, png_IDAT, data, size); - png_ptr->zstream.avail_out = 0; - png_ptr->zstream.next_out = NULL; - png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; - - png_ptr->zowner = 0; /* Release the stream */ - return; - } - - else - { - /* This is an error condition. */ - png_zstream_error(png_ptr, ret); - png_error(png_ptr, png_ptr->zstream.msg); - } - } -} - /* Write an IEND chunk */ void /* PRIVATE */ png_write_IEND(png_structrp png_ptr) @@ -1956,9 +1810,195 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) } #endif +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ +static void +png_start_IDAT(png_structrp png_ptr) +{ + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. + */ + if (png_ptr->zbuffer_list == NULL) + { + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; + } + + else + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; +} + +static void +png_compress_IDAT(png_structrp png_ptr, z_stream *zstream, + png_const_bytep input, uInt input_len, int flush) +{ + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. + */ + zstream->next_in = PNGZ_INPUT_CAST(input); + zstream->avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + zstream->avail_in = input_len; + input_len = 0; + + ret = deflate(zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += zstream->avail_in; + zstream->avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (zstream->avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + zstream->next_out = data; + zstream->avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - zstream->avail_out; + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + zstream->avail_out = 0; + zstream->next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(zstream, ret); + png_error(png_ptr, zstream->msg); + } + } +} + +#ifdef PNG_WRITE_FLUSH_SUPPORTED +/* Set the automatic flush interval or 0 to turn flushing off */ +void PNGAPI +png_set_flush(png_structrp png_ptr, int nrows) +{ + png_debug(1, "in png_set_flush"); + + if (png_ptr == NULL) + return; + + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); +} + +/* Flush the current output buffers now */ +void PNGAPI +png_write_flush(png_structrp png_ptr) +{ + png_debug(1, "in png_write_flush"); + + if (png_ptr == NULL) + return; + + /* Before the start of the IDAT and after the end of the image zowner will be + * something other than png_IDAT: + */ + if (png_ptr->zowner == png_IDAT) + { + png_compress_IDAT(png_ptr, &png_ptr->zstream, NULL, 0, Z_SYNC_FLUSH); + png_ptr->flush_rows = 0; + png_flush(png_ptr); + } +} +#endif /* WRITE_FLUSH */ + static void write_filtered_row(png_structrp png_ptr, png_const_bytep filtered_row, - png_uint_32 row_bytes, png_byte filter /*if at start of row*/, + unsigned int row_bytes, png_byte filter /*if at start of row*/, int end_of_image) { /* This handles writing a row that has been filtered, or did not need to be @@ -1967,22 +2007,24 @@ write_filtered_row(png_structrp png_ptr, png_const_bytep filtered_row, * only has one significant bit! */ debug(row_bytes > 0); + affirm(row_bytes <= ZLIB_IO_MAX); /* I.e. it fits in a uInt */ if (filter < PNG_FILTER_VALUE_LAST) /* start of row */ { png_byte buffer[1]; buffer[0] = filter; - png_compress_IDAT(png_ptr, buffer, 1U/*len*/, Z_NO_FLUSH); + png_compress_IDAT(png_ptr, &png_ptr->zstream, buffer, 1U/*len*/, + Z_NO_FLUSH); } - png_compress_IDAT(png_ptr, filtered_row, row_bytes, + png_compress_IDAT(png_ptr, &png_ptr->zstream, filtered_row, row_bytes, end_of_image ? Z_FINISH : Z_NO_FLUSH); } static void write_unfiltered_rowbits(png_structrp png_ptr, png_const_bytep filtered_row, - png_uint_32 row_bits, png_byte filter /*if at start of row*/, + unsigned int row_bits, png_byte filter /*if at start of row*/, int end_of_image) { /* Same as above, but it correctly clears the unused bits in a partial @@ -2012,7 +2054,7 @@ write_unfiltered_rowbits(png_structrp png_ptr, png_const_bytep filtered_row, #ifdef PNG_WRITE_FILTER_SUPPORTED static void -filter_block_singlebyte(png_alloc_size_t row_bytes, png_bytep sub_row, +filter_block_singlebyte(unsigned int row_bytes, png_bytep sub_row, png_bytep up_row, png_bytep avg_row, png_bytep paeth_row, png_const_bytep row, png_const_bytep prev_row, png_bytep prev_pixels) { @@ -2059,7 +2101,7 @@ filter_block_singlebyte(png_alloc_size_t row_bytes, png_bytep sub_row, } static void -filter_block_multibyte(png_alloc_size_t row_bytes, +filter_block_multibyte(unsigned int row_bytes, const unsigned int bpp, png_bytep sub_row, png_bytep up_row, png_bytep avg_row, png_bytep paeth_row, png_const_bytep row, png_const_bytep prev_row, png_bytep prev_pixels) @@ -2112,12 +2154,12 @@ filter_block_multibyte(png_alloc_size_t row_bytes, static void filter_row(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, - const png_uint_32 row_bits, unsigned int bpp, unsigned int filters_to_try, + unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, int start_of_row, int end_of_image) { /* filters_to_try identifies a single filter and it is not PNG_FILTER_NONE. */ - png_uint_32 row_bytes = row_bits >> 3; /* complete bytes */ + unsigned int row_bytes = row_bits >> 3; /* complete bytes */ png_byte filter = PNG_FILTER_VALUE_LAST /* not at start */; png_byte filtered_row[PNG_ROW_BUFFER_SIZE]; @@ -2188,7 +2230,7 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row, static void find_filter(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, - png_uint_32 row_bits, unsigned int bpp, unsigned int filters_to_try, + unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, int start_of_row, int end_of_image) { /* filters_to_try identifies multiple filters, up to all five. */ @@ -2211,15 +2253,20 @@ find_filter(png_structrp png_ptr, png_const_bytep prev_row, unsigned int /* PRIVATE */ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, - png_uint_32 width/*pixels*/, int first_row_in_pass, int last_pass_row, + unsigned int width/*pixels*/, int first_row_in_pass, int last_pass_row, unsigned int filters_to_try, int end_of_image) { png_bytep prev_row = png_ptr->row_buffer; const unsigned int bpp = png_ptr->row_output_pixel_depth; - const png_uint_32 row_bits = width * bpp; + const unsigned int row_bits = width * bpp; /* These invariants are expected from the caller: */ - affirm(width < 65536U && bpp <= 64U && row_bits <= 8U*PNG_ROW_BUFFER_SIZE); + affirm(width < 65536U && bpp <= 64U && width < 65536U/bpp && + row_bits <= 8U*PNG_ROW_BUFFER_SIZE); + + /* Set up the IDAT zlib compression if not set up yet: */ + if (png_ptr->zowner != png_IDAT) + png_start_IDAT(png_ptr); if (x == 0U) /* start of row */ { @@ -2264,6 +2311,23 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, } } } + + if (first_row_in_pass) + { + /* On the first row UP and NONE are the same, PAETH and SUB are the + * same, so if both members of a pair occur together eliminate the one + * that depends on the previous row. This will avoid the filter + * selection code while allowing the app to ensure all the filters can + * be used (prev_row is allocated) on the first row. + */ +# define match(mask) (filters_to_try & (mask)) == mask + if (match(PNG_FILTER_NONE+PNG_FILTER_UP)) + filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP); + + if (match(PNG_FILTER_SUB+PNG_FILTER_PAETH)) + filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP); +# undef match + } } /* start of row */ else if (prev_row != NULL) @@ -2362,7 +2426,7 @@ png_set_filter(png_structrp png_ptr, int method, int filtersIn) unsigned int /* PRIVATE */ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, - png_uint_32 width/*pixels*/, int first_row_in_pass, int last_pass_row, + unsigned int width/*pixels*/, int first_row_in_pass, int last_pass_row, unsigned int filters_to_try/*from previous call*/, int end_of_image) { const unsigned int bpp = png_ptr->row_output_pixel_depth; @@ -2371,7 +2435,12 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, row_bits = width; row_bits *= bpp; /* These invariants are expected from the caller: */ - affirm(width < 65536U && bpp <= 64U && row_bits <= 8U*PNG_ROW_BUFFER_SIZE); + affirm(width < 65536U && bpp <= 64U && width < 65536U/bpp && + row_bits <= 8U*PNG_ROW_BUFFER_SIZE); + + /* Set up the IDAT zlib compression if not set up yet: */ + if (png_ptr->zowner != png_IDAT) + png_start_IDAT(png_ptr); write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, end_of_image);