diff --git a/ANNOUNCE b/ANNOUNCE index d90e94f0a..a63957d7a 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -282,6 +282,9 @@ Version 1.6.0beta16 [March 6, 2012] changed parameters on deflate rather than always calling deflatedEnd/deflateInit. Validate the zTXt strings in pngvalid. + Added code to validate the windowBits value passed to deflateInit2(). + If the call to deflateInit2() is wrong a png_warning will be issued + (in fact this is harmless, but the PNG data produced may be sub-optimal). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index e028a08f8..9d2535156 100644 --- a/CHANGES +++ b/CHANGES @@ -4033,6 +4033,9 @@ Version 1.6.0beta16 [March 6, 2012] changed parameters on deflate rather than always calling deflatedEnd/deflateInit. Validate the zTXt strings in pngvalid. + Added code to validate the windowBits value passed to deflateInit2(). + If the call to deflateInit2() is wrong a png_warning will be issued + (in fact this is harmless, but the PNG data produced may be sub-optimal). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pngpriv.h b/pngpriv.h index c9d69bfab..3e351f3a6 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -513,7 +513,7 @@ typedef const png_uint_16p * png_const_uint_16pp; #define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ #define PNG_FLAG_ZSTREAM_IN_USE 0x0004 /* Added to libpng-1.6.0 */ #define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ - /* 0x0010 unused */ +#define PNG_FLAG_ZSTREAM_CMF_FIXUP 0x0010 /* Added to libpng-1.6.0 */ /* 0x0020 unused */ #define PNG_FLAG_ROW_INIT 0x0040 #define PNG_FLAG_FILLER_AFTER 0x0080 diff --git a/pngstruct.h b/pngstruct.h index 87ea234b0..fb29b5477 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -65,9 +65,9 @@ struct png_struct_def png_uint_32 flags; /* flags indicating various things to libpng */ png_uint_32 transformations; /* which transformations to perform */ - z_stream zstream; /* pointer to decompression structure (below) */ + z_stream zstream; /* decompression structure */ png_bytep zbuf; /* buffer for zlib */ - uInt zbuf_size; /* size of zbuf (typically 65536) */ + uInt zbuf_size; /* size of zbuf */ #ifdef PNG_WRITE_SUPPORTED int zlib_level; /* holds zlib compression level */ diff --git a/pngwutil.c b/pngwutil.c index b5b21b6ed..d4a50f6af 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -305,7 +305,11 @@ png_deflate_claim(png_structrp png_ptr, int for_IDAT, } /* Adjust 'windowBits' down if larger than 'data_size'; to stop this - * happening just pass 32768 as the data_size parameter. + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) */ if (data_size <= 256) windowBits = 8; @@ -318,6 +322,20 @@ png_deflate_claim(png_structrp png_ptr, int for_IDAT, --windowBits; } + if (windowBits < 15) + { + png_uint_32 test = 1U << windowBits; + + if (data_size + 262U > test) + { + ++windowBits; + png_ptr->flags |= PNG_FLAG_ZSTREAM_CMF_FIXUP; + } + + else + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_CMF_FIXUP; + } + /* Check against the previous initialized values, if any. */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) && (png_ptr->zlib_set_level != level || @@ -630,6 +648,7 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { unsigned int z_cinfo; unsigned int half_z_window_size; + int reduced = 0; png_size_t uncompressed_text_size = comp->input_len; z_cinfo = z_cmf >> 4; @@ -640,8 +659,12 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { z_cinfo--; half_z_window_size >>= 1; + reduced = 1; } + if (reduced && !(png_ptr->flags & PNG_FLAG_ZSTREAM_CMF_FIXUP)) + png_warning(png_ptr, "internal data size error (text)"); + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); if (comp->num_output_ptr) @@ -960,25 +983,10 @@ png_write_IDAT(png_structrp png_ptr, png_bytep data, png_size_t length) if (length >= 2 && png_ptr->height < 16384 && png_ptr->width < 16384) { - /* Compute the maximum possible length of the datastream */ - - /* Number of pixels, plus for each row a filter byte - * and possibly a padding byte, so increase the maximum - * size to account for these. - */ unsigned int z_cinfo; unsigned int half_z_window_size; - png_uint_32 uncompressed_idat_size = png_ptr->height * - ((png_ptr->width * - png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - - /* If it's interlaced, each block of 8 rows is sent as up to - * 14 rows, i.e., 6 additional rows, each with a filter byte - * and possibly a padding byte - */ - if (png_ptr->interlaced) - uncompressed_idat_size += ((png_ptr->height + 7)/8) * - (png_ptr->bit_depth < 8 ? 12 : 6); + int reduced = 0; + png_alloc_size_t uncompressed_idat_size = png_image_size(png_ptr); z_cinfo = z_cmf >> 4; half_z_window_size = 1 << (z_cinfo + 7); @@ -988,8 +996,12 @@ png_write_IDAT(png_structrp png_ptr, png_bytep data, png_size_t length) { z_cinfo--; half_z_window_size >>= 1; + reduced = 1; } + if (reduced && !(png_ptr->flags & PNG_FLAG_ZSTREAM_CMF_FIXUP)) + png_warning(png_ptr, "internal data size error (IDAT)"); + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); if (data[0] != z_cmf)