diff options
Diffstat (limited to 'third_party/libpng16/pngread.c')
-rw-r--r-- | third_party/libpng16/pngread.c | 150 |
1 files changed, 93 insertions, 57 deletions
diff --git a/third_party/libpng16/pngread.c b/third_party/libpng16/pngread.c index 9cb4d2e41d..0572c208cc 100644 --- a/third_party/libpng16/pngread.c +++ b/third_party/libpng16/pngread.c @@ -2,7 +2,7 @@ /* pngread.c - read a PNG file * * Last changed in libpng 1.6.17 [March 26, 2015] - * Copyright (c) 1998-2015 Glenn Randers-Pehrson + * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -127,7 +127,10 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) } else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + { + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; png_ptr->mode |= PNG_AFTER_IDAT; + } /* This should be a binary subdivision search or a hash for * matching the chunk name rather than a linear search. @@ -785,6 +788,9 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; + if (chunk_name != png_IDAT) + png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + if (chunk_name == png_IEND) png_handle_IEND(png_ptr, info_ptr, length); @@ -799,9 +805,9 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) { if (chunk_name == png_IDAT) { - if ((length > 0) || - (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) - png_benign_error(png_ptr, "Too many IDATs found"); + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, ".Too many IDATs found"); } png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) @@ -812,10 +818,14 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) else if (chunk_name == png_IDAT) { /* Zero length IDATs are legal after the last IDAT has been - * read, but not after other chunks have been read. + * read, but not after other chunks have been read. 1.6 does not + * always read all the deflate data; specifically it cannot be relied + * upon to read the Adler32 at the end. If it doesn't ignore IDAT + * chunks which are longer than zero as well: */ - if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) - png_benign_error(png_ptr, "Too many IDATs found"); + if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) + || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) + png_benign_error(png_ptr, "..Too many IDATs found"); png_crc_finish(png_ptr, length); } @@ -3848,16 +3858,16 @@ png_image_read_direct(png_voidp argument) else filler = 255; -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) - { - where = PNG_FILLER_BEFORE; - change &= ~PNG_FORMAT_FLAG_AFIRST; - } +#ifdef PNG_FORMAT_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } - else -# endif - where = PNG_FILLER_AFTER; + else +#endif + where = PNG_FILLER_AFTER; png_set_add_alpha(png_ptr, filler, where); } @@ -3965,12 +3975,12 @@ png_image_read_direct(png_voidp argument) if (info_ptr->bit_depth == 16) info_format |= PNG_FORMAT_FLAG_LINEAR; -# ifdef PNG_FORMAT_BGR_SUPPORTED - if ((png_ptr->transformations & PNG_BGR) != 0) - info_format |= PNG_FORMAT_FLAG_BGR; -# endif +#ifdef PNG_FORMAT_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + info_format |= PNG_FORMAT_FLAG_BGR; +#endif -# ifdef PNG_FORMAT_AFIRST_SUPPORTED +#ifdef PNG_FORMAT_AFIRST_SUPPORTED if (do_local_background == 2) { if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) @@ -4071,58 +4081,84 @@ png_image_finish_read(png_imagep image, png_const_colorp background, { if (image != NULL && image->version == PNG_IMAGE_VERSION) { - png_uint_32 check; + /* Check for row_stride overflow. This check is not performed on the + * original PNG format because it may not occur in the output PNG format + * and libpng deals with the issues of reading the original. + */ + const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); - if (row_stride == 0) - row_stride = PNG_IMAGE_ROW_STRIDE(*image); + if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */ + { + png_uint_32 check; + const png_uint_32 png_row_stride = image->width * channels; - if (row_stride < 0) - check = -row_stride; + if (row_stride == 0) + row_stride = (png_int_32)/*SAFE*/png_row_stride; - else - check = row_stride; + if (row_stride < 0) + check = -row_stride; - if (image->opaque != NULL && buffer != NULL && - check >= PNG_IMAGE_ROW_STRIDE(*image)) - { - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || - (image->colormap_entries > 0 && colormap != NULL)) + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) { - int result; - png_image_read_control display; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.background = background; - display.local_row = NULL; - - /* Choose the correct 'end' routine; for the color-map case all the - * setup has already been done. + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. */ - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) - result = - png_safe_execute(image, png_image_read_colormap, &display) && - png_safe_execute(image, png_image_read_colormapped, &display); + if (image->height <= 0xFFFFFFFF/png_row_stride) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case + * all the setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = png_safe_execute(image, + png_image_read_colormap, &display) && + png_safe_execute(image, + png_image_read_colormapped, &display); - else - result = - png_safe_execute(image, png_image_read_direct, &display); + else + result = + png_safe_execute(image, + png_image_read_direct, &display); + + png_image_free(image); + return result; + } - png_image_free(image); - return result; + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } + + else + return png_image_error(image, + "png_image_finish_read: image too large"); } else return png_image_error(image, - "png_image_finish_read[color-map]: no color-map"); + "png_image_finish_read: invalid argument"); } else return png_image_error(image, - "png_image_finish_read: invalid argument"); + "png_image_finish_read: row_stride too large"); } else if (image != NULL) |