mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	Filter code change prep.
This commit moves code round and changes the filter write interfaces that took png_uint_32 buffer pixel counts to unsigned int. Also moves compression code and definitions into pngwutil.c so that the compression code is isolated from other definitions. Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
		
							parent
							
								
									14d11b9f35
								
							
						
					
					
						commit
						b3a18efebf
					
				
							
								
								
									
										24
									
								
								png.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								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. |  * like Z_OK or Z_STREAM_END where the error code is apparently a success code. | ||||||
|  */ |  */ | ||||||
| void /* PRIVATE */ | 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
 |    /* 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 |     * 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. |     * 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: |       default: | ||||||
|       case Z_OK: |       case Z_OK: | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); |          zstream->msg = PNGZ_MSG_CAST("unexpected zlib return code"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_STREAM_END: |       case Z_STREAM_END: | ||||||
|          /* Normal exit */ |          /* 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; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_NEED_DICT: |       case Z_NEED_DICT: | ||||||
|          /* This means the deflate stream did not have a dictionary; this
 |          /* This means the deflate stream did not have a dictionary; this
 | ||||||
|           * indicates a bogus PNG. |           * indicates a bogus PNG. | ||||||
|           */ |           */ | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); |          zstream->msg = PNGZ_MSG_CAST("missing LZ dictionary"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_ERRNO: |       case Z_ERRNO: | ||||||
|          /* gz APIs only: should not happen */ |          /* 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; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_STREAM_ERROR: |       case Z_STREAM_ERROR: | ||||||
|          /* internal libpng 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; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_DATA_ERROR: |       case Z_DATA_ERROR: | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); |          zstream->msg = PNGZ_MSG_CAST("damaged LZ stream"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_MEM_ERROR: |       case Z_MEM_ERROR: | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); |          zstream->msg = PNGZ_MSG_CAST("insufficient memory"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_BUF_ERROR: |       case Z_BUF_ERROR: | ||||||
|          /* End of input or output; not a problem if the caller is doing
 |          /* End of input or output; not a problem if the caller is doing
 | ||||||
|           * incremental read or write. |           * incremental read or write. | ||||||
|           */ |           */ | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); |          zstream->msg = PNGZ_MSG_CAST("truncated"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case Z_VERSION_ERROR: |       case Z_VERSION_ERROR: | ||||||
|          png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); |          zstream->msg = PNGZ_MSG_CAST("unsupported zlib version"); | ||||||
|          break; |          break; | ||||||
| 
 | 
 | ||||||
|       case PNG_UNEXPECTED_ZLIB_RETURN: |       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", |           * and change pngpriv.h.  Note that this message is "... return", | ||||||
|           * whereas the default/Z_OK one is "... return code". |           * 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; |          break; | ||||||
|    } |    } | ||||||
| } | } | ||||||
|  | |||||||
| @ -953,7 +953,7 @@ PNG_INTERNAL_FUNCTION(void, png_copy_row,(png_const_structrp png_ptr, | |||||||
| 
 | 
 | ||||||
| /* Zlib support */ | /* Zlib support */ | ||||||
| #define PNG_UNEXPECTED_ZLIB_RETURN (-7) | #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); |    PNG_EMPTY); | ||||||
|    /* Used by the zlib handling functions to ensure that z_stream::msg is always
 |    /* Used by the zlib handling functions to ensure that z_stream::msg is always
 | ||||||
|     * set before they return. |     * 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_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, | ||||||
|    png_const_colorp palette, unsigned int num_pal),PNG_EMPTY); |    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); | PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); | ||||||
| 
 | 
 | ||||||
| #ifdef PNG_WRITE_gAMA_SUPPORTED | #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_INTERNAL_FUNCTION(unsigned int, png_write_filter_row, | ||||||
|    (png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_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 last_pass_row, unsigned int filters_to_try/*from previous call*/, | ||||||
|     int end_of_image), |     int end_of_image), | ||||||
|    PNG_EMPTY); |    PNG_EMPTY); | ||||||
|  | |||||||
| @ -751,7 +751,7 @@ png_read_destroy(png_structrp png_ptr) | |||||||
| 
 | 
 | ||||||
|       if (ret != Z_OK) |       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); |          png_warning(png_ptr, png_ptr->zstream.msg); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								pngrutil.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								pngrutil.c
									
									
									
									
									
								
							| @ -362,7 +362,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) | |||||||
| 
 | 
 | ||||||
|       else |       else | ||||||
|       { |       { | ||||||
|          png_zstream_error(png_ptr, ret); |          png_zstream_error(&png_ptr->zstream, ret); | ||||||
|          png_ptr->zstream_ended = 1; |          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) |       if (ret != Z_BUF_ERROR) | ||||||
|          png_ptr->zstream_ended = 1; |          png_ptr->zstream_ended = 1; | ||||||
| 
 | 
 | ||||||
|       png_zstream_error(png_ptr, ret); |       png_zstream_error(&png_ptr->zstream, ret); | ||||||
|       return ret; |       return ret; | ||||||
|    } |    } | ||||||
| 
 | 
 | ||||||
| @ -667,14 +667,14 @@ png_decompress_chunk(png_structrp png_ptr, | |||||||
|                { |                { | ||||||
|                   /* Out of memory allocating the buffer */ |                   /* Out of memory allocating the buffer */ | ||||||
|                   ret = Z_MEM_ERROR; |                   ret = Z_MEM_ERROR; | ||||||
|                   png_zstream_error(png_ptr, Z_MEM_ERROR); |                   png_zstream_error(&png_ptr->zstream, Z_MEM_ERROR); | ||||||
|                } |                } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                /* inflateReset failed, store the error message */ |                /* inflateReset failed, store the error message */ | ||||||
|                png_zstream_error(png_ptr, ret); |                png_zstream_error(&png_ptr->zstream, ret); | ||||||
| 
 | 
 | ||||||
|                if (ret == Z_STREAM_END) |                if (ret == Z_STREAM_END) | ||||||
|                   ret = PNG_UNEXPECTED_ZLIB_RETURN; |                   ret = PNG_UNEXPECTED_ZLIB_RETURN; | ||||||
| @ -697,7 +697,7 @@ png_decompress_chunk(png_structrp png_ptr, | |||||||
|    else |    else | ||||||
|    { |    { | ||||||
|       /* Application/configuration limits exceeded */ |       /* 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; |       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 */ |       png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ | ||||||
| 
 | 
 | ||||||
|       /* Ensure the error message pointer is always set: */ |       /* Ensure the error message pointer is always set: */ | ||||||
|       png_zstream_error(png_ptr, ret); |       png_zstream_error(&png_ptr->zstream, ret); | ||||||
|       return 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
 |          /* This is just a warning; it's safe, and the zstream_error flag is
 | ||||||
|           * not set. |           * not set. | ||||||
|           */ |           */ | ||||||
|          png_zstream_error(png_ptr, ret); |          png_zstream_error(&png_ptr->zstream, ret); | ||||||
|          png_chunk_warning(png_ptr, png_ptr->zstream.msg); |          png_chunk_warning(png_ptr, png_ptr->zstream.msg); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								pngstruct.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								pngstruct.h
									
									
									
									
									
								
							| @ -64,14 +64,7 @@ | |||||||
| 
 | 
 | ||||||
| #ifdef PNG_WRITE_SUPPORTED | #ifdef PNG_WRITE_SUPPORTED | ||||||
| /* The type of a compression buffer list used by the write code. */ | /* The type of a compression buffer list used by the write code. */ | ||||||
| typedef struct png_compression_buffer | typedef struct png_compression_buffer *png_compression_bufferp; | ||||||
| { |  | ||||||
|    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) |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Colorspace support; structures used in png_struct, png_info and in internal
 | /* 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 */ |    png_uint_32  zowner;        /* ID (chunk type) of zstream owner, 0 if none */ | ||||||
|    z_stream     zstream;       /* decompression structure */ |    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_ended:1; /* no more zlib output available */ | ||||||
|    unsigned int zstream_error:1; /* zlib error message has been output */ |    unsigned int zstream_error:1; /* zlib error message has been output */ | ||||||
|    unsigned int zstream_eod  :1; /* all the required uncompressed data has been
 |    unsigned int zstream_eod  :1; /* all the required uncompressed data has been
 | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								pngwrite.c
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								pngwrite.c
									
									
									
									
									
								
							| @ -1093,40 +1093,6 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) | |||||||
|    } /* png_ptr != NULL */ |    } /* 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. */ | /* Free any memory used in png_ptr struct without freeing the struct itself. */ | ||||||
| static void | static void | ||||||
| png_write_destroy(png_structrp png_ptr) | png_write_destroy(png_structrp png_ptr) | ||||||
| @ -1140,7 +1106,7 @@ png_write_destroy(png_structrp png_ptr) | |||||||
| 
 | 
 | ||||||
|       if (ret != Z_OK) |       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); |          png_warning(png_ptr, png_ptr->zstream.msg); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
|  | |||||||
							
								
								
									
										417
									
								
								pngwutil.c
									
									
									
									
									
								
							
							
						
						
									
										417
									
								
								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.) |  * point at which a lower LZ window size can be used.) | ||||||
|  */ |  */ | ||||||
| static png_alloc_size_t | 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
 |    /* Only return sizes up to the maximum of a png_uint_32; do this by limiting
 | ||||||
|     * the width and height used to 15 bits. |     * the width and height used to 15 bits. | ||||||
| @ -242,6 +242,16 @@ png_image_size(png_structrp png_ptr) | |||||||
|       return 0xffffffffU; |       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 | #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED | ||||||
|    /* This is the code to hack the first two bytes of the deflate stream (the
 |    /* 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 |     * 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) |          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_warning(png_ptr, png_ptr->zstream.msg); | ||||||
|             png_ptr->zstream.state = NULL; /* zlib error recovery */ |             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; |          png_ptr->zowner = owner; | ||||||
| 
 | 
 | ||||||
|       else |       else | ||||||
|          png_zstream_error(png_ptr, ret); |          png_zstream_error(&png_ptr->zstream, ret); | ||||||
| 
 | 
 | ||||||
|       return ret; |       return ret; | ||||||
|    } |    } | ||||||
| @ -616,7 +626,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       else |       else | ||||||
|          png_zstream_error(png_ptr, ret); |          png_zstream_error(&png_ptr->zstream, ret); | ||||||
| 
 | 
 | ||||||
|       /* Reset zlib for another zTXt/iTXt or image data */ |       /* Reset zlib for another zTXt/iTXt or image data */ | ||||||
|       png_ptr->zowner = 0; |       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; |    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 */ | /* Write an IEND chunk */ | ||||||
| void /* PRIVATE */ | void /* PRIVATE */ | ||||||
| png_write_IEND(png_structrp png_ptr) | png_write_IEND(png_structrp png_ptr) | ||||||
| @ -1956,9 +1810,195 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) | |||||||
| } | } | ||||||
| #endif | #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 | static void | ||||||
| write_filtered_row(png_structrp png_ptr, png_const_bytep filtered_row, | 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) |    int end_of_image) | ||||||
| { | { | ||||||
|    /* This handles writing a row that has been filtered, or did not need to be
 |    /* 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! |     * only has one significant bit! | ||||||
|     */ |     */ | ||||||
|    debug(row_bytes > 0); |    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 */ |    if (filter < PNG_FILTER_VALUE_LAST) /* start of row */ | ||||||
|    { |    { | ||||||
|       png_byte buffer[1]; |       png_byte buffer[1]; | ||||||
| 
 | 
 | ||||||
|       buffer[0] = filter; |       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); |          end_of_image ? Z_FINISH : Z_NO_FLUSH); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| write_unfiltered_rowbits(png_structrp png_ptr, png_const_bytep filtered_row, | 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) |    int end_of_image) | ||||||
| { | { | ||||||
|    /* Same as above, but it correctly clears the unused bits in a partial
 |    /* 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 | #ifdef PNG_WRITE_FILTER_SUPPORTED | ||||||
| static void | 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_bytep up_row, png_bytep avg_row, png_bytep paeth_row, | ||||||
|    png_const_bytep row, png_const_bytep prev_row, png_bytep prev_pixels) |    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 | 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, |    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_bytep avg_row, png_bytep paeth_row, png_const_bytep row, | ||||||
|    png_const_bytep prev_row, png_bytep prev_pixels) |    png_const_bytep prev_row, png_bytep prev_pixels) | ||||||
| @ -2112,12 +2154,12 @@ filter_block_multibyte(png_alloc_size_t row_bytes, | |||||||
| static void | static void | ||||||
| filter_row(png_structrp png_ptr, png_const_bytep prev_row, | filter_row(png_structrp png_ptr, png_const_bytep prev_row, | ||||||
|       png_bytep prev_pixels, png_const_bytep unfiltered_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) |       int start_of_row, int end_of_image) | ||||||
| { | { | ||||||
|    /* filters_to_try identifies a single filter and it is not PNG_FILTER_NONE.
 |    /* 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 filter = PNG_FILTER_VALUE_LAST /* not at start */; | ||||||
|    png_byte filtered_row[PNG_ROW_BUFFER_SIZE]; |    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 | static void | ||||||
| find_filter(png_structrp png_ptr, png_const_bytep prev_row, | find_filter(png_structrp png_ptr, png_const_bytep prev_row, | ||||||
|    png_bytep prev_pixels, png_const_bytep unfiltered_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) |    int start_of_row, int end_of_image) | ||||||
| { | { | ||||||
|    /* filters_to_try identifies multiple filters, up to all five. */ |    /* 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 */ | unsigned int /* PRIVATE */ | ||||||
| png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, | png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, | ||||||
|       png_const_bytep unfiltered_row, png_uint_32 x, |       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) |       unsigned int filters_to_try, int end_of_image) | ||||||
| { | { | ||||||
|    png_bytep prev_row = png_ptr->row_buffer; |    png_bytep prev_row = png_ptr->row_buffer; | ||||||
|    const unsigned int bpp = png_ptr->row_output_pixel_depth; |    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: */ |    /* 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 */ |    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 */ |    } /* start of row */ | ||||||
| 
 | 
 | ||||||
|    else if (prev_row != NULL) |    else if (prev_row != NULL) | ||||||
| @ -2362,7 +2426,7 @@ png_set_filter(png_structrp png_ptr, int method, int filtersIn) | |||||||
| unsigned int /* PRIVATE */ | unsigned int /* PRIVATE */ | ||||||
| png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, | png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, | ||||||
|       png_const_bytep unfiltered_row, png_uint_32 x, |       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) |       unsigned int filters_to_try/*from previous call*/, int end_of_image) | ||||||
| { | { | ||||||
|    const unsigned int bpp = png_ptr->row_output_pixel_depth; |    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 = width; | ||||||
|    row_bits *= bpp; |    row_bits *= bpp; | ||||||
|    /* These invariants are expected from the caller: */ |    /* 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, |    write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, | ||||||
|          x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, end_of_image); |          x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, end_of_image); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 John Bowler
						John Bowler