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. | ||||
|  */ | ||||
| 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; | ||||
|    } | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|       } | ||||
|    } | ||||
|  | ||||
							
								
								
									
										14
									
								
								pngrutil.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								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); | ||||
|       } | ||||
|    } | ||||
|  | ||||
							
								
								
									
										10
									
								
								pngstruct.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								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
 | ||||
|  | ||||
							
								
								
									
										36
									
								
								pngwrite.c
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								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); | ||||
|       } | ||||
|    } | ||||
|  | ||||
							
								
								
									
										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.) | ||||
|  */ | ||||
| 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); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 John Bowler
						John Bowler