X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0272a10d2e6d5323422c4c8600fe47ccac0df182..603cfe42185349e119ba4c69bd56a79998babcc4:/src/png/pngrutil.c?ds=inline diff --git a/src/png/pngrutil.c b/src/png/pngrutil.c index 99bca1933b..11e412b729 100644 --- a/src/png/pngrutil.c +++ b/src/png/pngrutil.c @@ -1,110 +1,133 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.2.19 August 19, 2007 - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2007 Glenn Randers-Pehrson + * Last changed in libpng 1.4.4 [August 26, 2010] + * Copyright (c) 1998-2010 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.) * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + * * This file contains routines that are only called from within * libpng itself during the course of reading an image. */ -#define PNG_INTERNAL +#define PNG_NO_PEDANTIC_WARNINGS #include "png.h" +#ifdef PNG_READ_SUPPORTED +#include "pngpriv.h" -#if defined(PNG_READ_SUPPORTED) - -#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500) -# define WIN32_WCE_OLD -#endif - -#ifdef PNG_FLOATING_POINT_SUPPORTED -# if defined(WIN32_WCE_OLD) -/* strtod() function is not supported on WindowsCE */ -__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, char **endptr) -{ - double result = 0; - int len; - wchar_t *str, *end; - - len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0); - str = (wchar_t *)png_malloc(png_ptr, len * sizeof(wchar_t)); - if ( NULL != str ) - { - MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len); - result = wcstod(str, &end); - len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL); - *endptr = (char *)nptr + (png_strlen(nptr) - len + 1); - png_free(png_ptr, str); - } - return result; -} -# else # define png_strtod(p,a,b) strtod(a,b) -# endif -#endif - png_uint_32 PNGAPI png_get_uint_31(png_structp png_ptr, png_bytep buf) { png_uint_32 i = png_get_uint_32(buf); if (i > PNG_UINT_31_MAX) - png_error(png_ptr, "PNG unsigned integer out of range."); + png_error(png_ptr, "PNG unsigned integer out of range"); return (i); } -#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED +#ifndef PNG_USE_READ_MACROS /* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ -png_uint_32 PNGAPI -png_get_uint_32(png_bytep buf) +png_uint_32 (PNGAPI +png_get_uint_32)(png_bytep buf) { - png_uint_32 i = ((png_uint_32)(*buf) << 24) + - ((png_uint_32)(*(buf + 1)) << 16) + - ((png_uint_32)(*(buf + 2)) << 8) + - (png_uint_32)(*(buf + 3)); + png_uint_32 i = + ((png_uint_32)(*(buf )) << 24) + + ((png_uint_32)(*(buf + 1)) << 16) + + ((png_uint_32)(*(buf + 2)) << 8) + + ((png_uint_32)(*(buf + 3)) ) ; return (i); } /* Grab a signed 32-bit integer from a buffer in big-endian format. The - * data is stored in the PNG file in two's complement format, and it is - * assumed that the machine format for signed integers is the same. */ -png_int_32 PNGAPI -png_get_int_32(png_bytep buf) + * data is stored in the PNG file in two's complement format and there + * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore + * the following code does a two's complement to native conversion. + */ +png_int_32 (PNGAPI +png_get_int_32)(png_bytep buf) { - png_int_32 i = ((png_int_32)(*buf) << 24) + - ((png_int_32)(*(buf + 1)) << 16) + - ((png_int_32)(*(buf + 2)) << 8) + - (png_int_32)(*(buf + 3)); + png_uint_32 u = png_get_uint_32(buf); + if ((u & 0x80000000) == 0) /* non-negative */ + return u; - return (i); + u = (u ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ + return -(png_int_32)u; } /* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ -png_uint_16 PNGAPI -png_get_uint_16(png_bytep buf) +png_uint_16 (PNGAPI +png_get_uint_16)(png_bytep buf) { - png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) + - (png_uint_16)(*(buf + 1))); + png_uint_16 i = + ((png_uint_32)(*buf) << 8) + + ((png_uint_32)(*(buf + 1))); return (i); } -#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */ +#endif /* PNG_USE_READ_MACROS */ + +/* Read the chunk header (length + type name). + * Put the type name into png_ptr->chunk_name, and return the length. + */ +png_uint_32 /* PRIVATE */ +png_read_chunk_header(png_structp png_ptr) +{ + png_byte buf[8]; + png_uint_32 length; + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being read. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + + /* Read the length and the chunk name */ + png_read_data(png_ptr, buf, 8); + length = png_get_uint_31(png_ptr, buf); + + /* Put the chunk name into png_ptr->chunk_name */ + png_memcpy(png_ptr->chunk_name, buf + 4, 4); + + png_debug2(0, "Reading %s chunk, length = %lu", + png_ptr->chunk_name, length); + + /* Reset the crc and run it over the chunk name */ + png_reset_crc(png_ptr); + png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); + + /* Check to see if chunk name is valid */ + png_check_chunk_name(png_ptr, png_ptr->chunk_name); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be read. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + + return length; +} /* Read data, and (optionally) run it through the CRC. */ void /* PRIVATE */ png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) { - if(png_ptr == NULL) return; + if (png_ptr == NULL) + return; png_read_data(png_ptr, buf, length); png_calculate_crc(png_ptr, buf, length); } /* Optionally skip data and then check the CRC. Depending on whether we - are reading a ancillary or critical chunk, and how the program has set - things up, we may calculate the CRC on the data and print a message. - Returns '1' if there was a CRC error, '0' otherwise. */ + * are reading a ancillary or critical chunk, and how the program has set + * things up, we may calculate the CRC on the data and print a message. + * Returns '1' if there was a CRC error, '0' otherwise. + */ int /* PRIVATE */ png_crc_finish(png_structp png_ptr, png_uint_32 skip) { @@ -123,7 +146,7 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip) if (png_crc_error(png_ptr)) { if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) { @@ -131,7 +154,8 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip) } else { - png_chunk_error(png_ptr, "CRC error"); + png_chunk_benign_error(png_ptr, "CRC error"); + return (0); } return (1); } @@ -140,7 +164,8 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip) } /* Compare the CRC stored in the PNG file with that calculated by libpng from - the data it has read thus far. */ + * the data it has read thus far. + */ int /* PRIVATE */ png_crc_error(png_structp png_ptr) { @@ -160,6 +185,12 @@ png_crc_error(png_structp png_ptr) need_crc = 0; } +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being read */ + /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + png_read_data(png_ptr, crc_bytes, 4); if (need_crc) @@ -173,177 +204,218 @@ png_crc_error(png_structp png_ptr) #if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ defined(PNG_READ_iCCP_SUPPORTED) -/* - * Decompress trailing data in a chunk. The assumption is that chunkdata - * points at an allocated area holding the contents of a chunk with a - * trailing compressed part. What we get back is an allocated area - * holding the original prefix part and an uncompressed version of the - * trailing part (the malloc area passed in is freed). - */ -png_charp /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_charp chunkdata, png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) +static png_size_t +png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size, + png_bytep output, png_size_t output_size) { - static PNG_CONST char msg[] = "Error decoding compressed text"; - png_charp text; - png_size_t text_size; + png_size_t count = 0; - if (comp_type == PNG_COMPRESSION_TYPE_BASE) + png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */ + png_ptr->zstream.avail_in = size; + + while (1) { - int ret = Z_OK; - png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size); - png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); + int ret, avail; + + /* Reset the output buffer each time round - we empty it + * after every inflate call. + */ png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.avail_out = png_ptr->zbuf_size; - text_size = 0; - text = NULL; + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; - while (png_ptr->zstream.avail_in) + /* First copy/count any new output - but only if we didn't + * get an error code. + */ + if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) { - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) + if (output != 0 && output_size > count) { - if (png_ptr->zstream.msg != NULL) - png_warning(png_ptr, png_ptr->zstream.msg); - else - png_warning(png_ptr, msg); - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; + int copy = output_size - count; + if (avail < copy) copy = avail; + png_memcpy(output + count, png_ptr->zbuf, copy); + } + count += avail; + } - if (text == NULL) - { - text_size = prefix_size + png_sizeof(msg) + 1; - text = (png_charp)png_malloc_warn(png_ptr, text_size); - if (text == NULL) - { - png_free(png_ptr,chunkdata); - png_error(png_ptr,"Not enough memory to decompress chunk"); - } - png_memcpy(text, chunkdata, prefix_size); - } + if (ret == Z_OK) + continue; - text[text_size - 1] = 0x00; + /* Termination conditions - always reset the zstream, it + * must be left in inflateInit state. + */ + png_ptr->zstream.avail_in = 0; + inflateReset(&png_ptr->zstream); - /* Copy what we can of the error message into the text chunk */ - text_size = (png_size_t)(chunklength - (text - chunkdata) - 1); - text_size = png_sizeof(msg) > text_size ? text_size : - png_sizeof(msg); - png_memcpy(text + prefix_size, msg, text_size + 1); - break; - } - if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) + if (ret == Z_STREAM_END) + return count; /* NOTE: may be zero. */ + + /* Now handle the error codes - the API always returns 0 + * and the error message is dumped into the uncompressed + * buffer if available. + */ + { + PNG_CONST char *msg; + if (png_ptr->zstream.msg != 0) + msg = png_ptr->zstream.msg; + else { - if (text == NULL) - { - text_size = prefix_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out; - text = (png_charp)png_malloc_warn(png_ptr, text_size + 1); - if (text == NULL) - { - png_free(png_ptr,chunkdata); - png_error(png_ptr,"Not enough memory to decompress chunk."); - } - png_memcpy(text + prefix_size, png_ptr->zbuf, - text_size - prefix_size); - png_memcpy(text, chunkdata, prefix_size); - *(text + text_size) = 0x00; - } - else - { - png_charp tmp; +#ifdef PNG_STDIO_SUPPORTED + char umsg[52]; - tmp = text; - text = (png_charp)png_malloc_warn(png_ptr, - (png_uint_32)(text_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); - if (text == NULL) - { - png_free(png_ptr, tmp); - png_free(png_ptr, chunkdata); - png_error(png_ptr,"Not enough memory to decompress chunk.."); - } - png_memcpy(text, tmp, text_size); - png_free(png_ptr, tmp); - png_memcpy(text + text_size, png_ptr->zbuf, - (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; - *(text + text_size) = 0x00; - } - if (ret == Z_STREAM_END) - break; - else + switch (ret) { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + case Z_BUF_ERROR: + msg = "Buffer error in compressed datastream in %s chunk"; + break; + case Z_DATA_ERROR: + msg = "Data error in compressed datastream in %s chunk"; + break; + default: + msg = "Incomplete compressed datastream in %s chunk"; + break; } + + png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); + msg = umsg; +#else + msg = "Damaged compressed datastream in chunk other than IDAT"; +#endif } + + png_warning(png_ptr, msg); } - if (ret != Z_STREAM_END) - { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) - char umsg[52]; - - if (ret == Z_BUF_ERROR) - png_snprintf(umsg, 52, - "Buffer error in compressed datastream in %s chunk", - png_ptr->chunk_name); - else if (ret == Z_DATA_ERROR) - png_snprintf(umsg, 52, - "Data error in compressed datastream in %s chunk", - png_ptr->chunk_name); - else - png_snprintf(umsg, 52, - "Incomplete compressed datastream in %s chunk", - png_ptr->chunk_name); - png_warning(png_ptr, umsg); + + /* 0 means an error - notice that this code simple ignores + * zero length compressed chunks as a result. + */ + return 0; + } +} + +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * points at an allocated area holding the contents of a chunk with a + * trailing compressed part. What we get back is an allocated area + * holding the original prefix part and an uncompressed version of the + * trailing part (the malloc area passed in is freed). + */ +void /* PRIVATE */ +png_decompress_chunk(png_structp png_ptr, int comp_type, + png_size_t chunklength, + png_size_t prefix_size, png_size_t *newlength) +{ + /* The caller should guarantee this */ + if (prefix_size > chunklength) + { + /* The recovery is to delete the chunk. */ + png_warning(png_ptr, "invalid chunklength"); + prefix_size = 0; /* To delete everything */ + } + + else if (comp_type == PNG_COMPRESSION_TYPE_BASE) + { + png_size_t expanded_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + 0/*output*/, 0/*output size*/); + + /* Now check the limits on this chunk - if the limit fails the + * compressed data will be removed, the prefix will remain. + */ +#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max && + (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) #else - png_warning(png_ptr, - "Incomplete compressed datastream in chunk other than IDAT"); +# ifdef PNG_USER_CHUNK_MALLOC_MAX + if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && + prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) +# endif #endif - text_size=prefix_size; - if (text == NULL) + png_warning(png_ptr, "Exceeded size limit while expanding chunk"); + + /* If the size is zero either there was an error and a message + * has already been output (warning) or the size really is zero + * and we have nothing to do - the code will exit through the + * error case below. + */ +#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \ + defined(PNG_USER_CHUNK_MALLOC_MAX) + else +#endif + if (expanded_size > 0) + { + /* Success (maybe) - really uncompress the chunk. */ + png_size_t new_size = 0; + png_charp text = png_malloc_warn(png_ptr, + prefix_size + expanded_size + 1); + + if (text != NULL) { - text = (png_charp)png_malloc_warn(png_ptr, text_size+1); - if (text == NULL) - { - png_free(png_ptr, chunkdata); - png_error(png_ptr,"Not enough memory for text."); - } - png_memcpy(text, chunkdata, prefix_size); + png_memcpy(text, png_ptr->chunkdata, prefix_size); + new_size = png_inflate(png_ptr, + (png_bytep)(png_ptr->chunkdata + prefix_size), + chunklength - prefix_size, + (png_bytep)(text + prefix_size), expanded_size); + text[prefix_size + expanded_size] = 0; /* just in case */ + + if (new_size == expanded_size) + { + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + *newlength = prefix_size + expanded_size; + return; /* The success return! */ + } + + png_warning(png_ptr, "png_inflate logic error"); + png_free(png_ptr, text); } - *(text + text_size) = 0x00; + else + png_warning(png_ptr, "Not enough memory to decompress chunk"); } - - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; - - png_free(png_ptr, chunkdata); - chunkdata = text; - *newlength=text_size; } + else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ { -#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) +#ifdef PNG_STDIO_SUPPORTED char umsg[50]; - png_snprintf(umsg, 50, - "Unknown zTXt compression type %d", comp_type); + png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", + comp_type); png_warning(png_ptr, umsg); #else png_warning(png_ptr, "Unknown zTXt compression type"); #endif - *(chunkdata + prefix_size) = 0x00; - *newlength=prefix_size; + /* The recovery is to simply drop the data. */ } - return chunkdata; + /* Generic error return - leave the prefix, delete the compressed + * data, reallocate the chunkdata to remove the potentially large + * amount of compressed data. + */ + { + png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); + if (text != NULL) + { + if (prefix_size > 0) + png_memcpy(text, png_ptr->chunkdata, prefix_size); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = text; + + /* This is an extra zero in the 'uncompressed' part. */ + *(png_ptr->chunkdata + prefix_size) = 0x00; + } + /* Ignore a malloc error here - it is safe. */ + } + + *newlength = prefix_size; } #endif -/* read and check the IDHR chunk */ +/* Read and check the IDHR chunk */ void /* PRIVATE */ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { @@ -352,12 +424,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) int bit_depth, color_type, compression_type, filter_type; int interlace_type; - png_debug(1, "in png_handle_IHDR\n"); + png_debug(1, "in png_handle_IHDR"); if (png_ptr->mode & PNG_HAVE_IHDR) png_error(png_ptr, "Out of place IHDR"); - /* check the length */ + /* Check the length */ if (length != 13) png_error(png_ptr, "Invalid IHDR chunk"); @@ -374,66 +446,71 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) filter_type = buf[11]; interlace_type = buf[12]; - /* set internal variables */ + /* Set internal variables */ png_ptr->width = width; png_ptr->height = height; png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->interlaced = (png_byte)interlace_type; png_ptr->color_type = (png_byte)color_type; -#if defined(PNG_MNG_FEATURES_SUPPORTED) +#ifdef PNG_MNG_FEATURES_SUPPORTED png_ptr->filter_type = (png_byte)filter_type; #endif png_ptr->compression_type = (png_byte)compression_type; - /* find number of channels */ + /* Find number of channels */ switch (png_ptr->color_type) { case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: png_ptr->channels = 1; break; + case PNG_COLOR_TYPE_RGB: png_ptr->channels = 3; break; + case PNG_COLOR_TYPE_GRAY_ALPHA: png_ptr->channels = 2; break; + case PNG_COLOR_TYPE_RGB_ALPHA: png_ptr->channels = 4; break; } - /* set up other useful info */ + /* Set up other useful info */ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); - png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width); - png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth); - png_debug1(3,"channels = %d\n", png_ptr->channels); - png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes); + png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); + png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); + png_debug1(3, "channels = %d", png_ptr->channels); + png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); } -/* read and check the palette */ +/* Read and check the palette */ void /* PRIVATE */ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; int num, i; -#ifndef PNG_NO_POINTER_INDEXING +#ifdef PNG_POINTER_INDEXING_SUPPORTED png_colorp pal_ptr; #endif - png_debug(1, "in png_handle_PLTE\n"); + png_debug(1, "in png_handle_PLTE"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before PLTE"); + else if (png_ptr->mode & PNG_HAVE_IDAT) { png_warning(png_ptr, "Invalid PLTE after IDAT"); png_crc_finish(png_ptr, length); return; } + else if (png_ptr->mode & PNG_HAVE_PLTE) png_error(png_ptr, "Duplicate PLTE chunk"); @@ -446,7 +523,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) +#ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { png_crc_finish(png_ptr, length); @@ -462,6 +539,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, length); return; } + else { png_error(png_ptr, "Invalid palette chunk"); @@ -470,7 +548,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) num = (int)length / 3; -#ifndef PNG_NO_POINTER_INDEXING +#ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) { png_byte buf[3]; @@ -486,7 +564,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_byte buf[3]; png_crc_read(png_ptr, buf, 3); - /* don't depend upon png_color being any order */ + /* Don't depend upon png_color being any order */ palette[i].red = buf[0]; palette[i].green = buf[1]; palette[i].blue = buf[2]; @@ -494,16 +572,17 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #endif /* If we actually NEED the PLTE chunk (ie for a paletted image), we do - whatever the normal CRC configuration tells us. However, if we - have an RGB image, the PLTE can be considered ancillary, so - we will act as though it is. */ -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. + */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) #endif { png_crc_finish(png_ptr, 0); } -#if !defined(PNG_READ_OPT_PLTE_SUPPORTED) +#ifndef PNG_READ_OPT_PLTE_SUPPORTED else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ { /* If we don't want to use the data from an ancillary chunk, @@ -514,7 +593,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) { - png_chunk_error(png_ptr, "CRC error"); + png_chunk_benign_error(png_ptr, "CRC error"); } else { @@ -532,7 +611,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_set_PLTE(png_ptr, info_ptr, palette, num); -#if defined(PNG_READ_tRNS_SUPPORTED) +#ifdef PNG_READ_tRNS_SUPPORTED if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) @@ -556,7 +635,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void /* PRIVATE */ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_debug(1, "in png_handle_IEND\n"); + png_debug(1, "in png_handle_IEND"); if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) { @@ -571,10 +650,10 @@ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_finish(png_ptr, length); - info_ptr =info_ptr; /* quiet compiler warnings about unused info_ptr */ + info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ } -#if defined(PNG_READ_gAMA_SUPPORTED) +#ifdef PNG_READ_gAMA_SUPPORTED void /* PRIVATE */ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { @@ -584,7 +663,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #endif png_byte buf[4]; - png_debug(1, "in png_handle_gAMA\n"); + png_debug(1, "in png_handle_gAMA"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before gAMA"); @@ -599,7 +678,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_warning(png_ptr, "Out of place gAMA chunk"); if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#if defined(PNG_READ_sRGB_SUPPORTED) +#ifdef PNG_READ_sRGB_SUPPORTED && !(info_ptr->valid & PNG_INFO_sRGB) #endif ) @@ -621,7 +700,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; igamma = (png_fixed_point)png_get_uint_32(buf); - /* check for zero gamma */ + /* Check for zero gamma */ if (igamma == 0) { png_warning(png_ptr, @@ -629,14 +708,14 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } -#if defined(PNG_READ_sRGB_SUPPORTED) +#ifdef PNG_READ_sRGB_SUPPORTED if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO - fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma); +#ifdef PNG_CONSOLE_IO_SUPPORTED + fprintf(stderr, "gamma = (%d/100000)", (int)igamma); #endif return; } @@ -655,14 +734,14 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_sBIT_SUPPORTED) +#ifdef PNG_READ_sBIT_SUPPORTED void /* PRIVATE */ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_size_t truelen; png_byte buf[4]; - png_debug(1, "in png_handle_sBIT\n"); + png_debug(1, "in png_handle_sBIT"); buf[0] = buf[1] = buf[2] = buf[3] = 0; @@ -721,11 +800,11 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_cHRM_SUPPORTED) +#ifdef PNG_READ_cHRM_SUPPORTED void /* PRIVATE */ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_byte buf[4]; + png_byte buf[32]; #ifdef PNG_FLOATING_POINT_SUPPORTED float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; #endif @@ -734,7 +813,7 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_uint_32 uint_x, uint_y; - png_debug(1, "in png_handle_cHRM\n"); + png_debug(1, "in png_handle_cHRM"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before cHRM"); @@ -749,7 +828,7 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_warning(png_ptr, "Missing PLTE before cHRM"); if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -#if defined(PNG_READ_sRGB_SUPPORTED) +#ifdef PNG_READ_sRGB_SUPPORTED && !(info_ptr->valid & PNG_INFO_sRGB) #endif ) @@ -766,64 +845,27 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - png_crc_read(png_ptr, buf, 4); - uint_x = png_get_uint_32(buf); - - png_crc_read(png_ptr, buf, 4); - uint_y = png_get_uint_32(buf); - - if (uint_x > 80000L || uint_y > 80000L || - uint_x + uint_y > 100000L) - { - png_warning(png_ptr, "Invalid cHRM white point"); - png_crc_finish(png_ptr, 24); + png_crc_read(png_ptr, buf, 32); + if (png_crc_finish(png_ptr, 0)) return; - } - int_x_white = (png_fixed_point)uint_x; - int_y_white = (png_fixed_point)uint_y; - png_crc_read(png_ptr, buf, 4); uint_x = png_get_uint_32(buf); + uint_y = png_get_uint_32(buf + 4); + int_x_white = (png_fixed_point)uint_x; + int_y_white = (png_fixed_point)uint_y; - png_crc_read(png_ptr, buf, 4); - uint_y = png_get_uint_32(buf); - - if (uint_x + uint_y > 100000L) - { - png_warning(png_ptr, "Invalid cHRM red point"); - png_crc_finish(png_ptr, 16); - return; - } + uint_x = png_get_uint_32(buf + 8); + uint_y = png_get_uint_32(buf + 12); int_x_red = (png_fixed_point)uint_x; int_y_red = (png_fixed_point)uint_y; - png_crc_read(png_ptr, buf, 4); - uint_x = png_get_uint_32(buf); - - png_crc_read(png_ptr, buf, 4); - uint_y = png_get_uint_32(buf); - - if (uint_x + uint_y > 100000L) - { - png_warning(png_ptr, "Invalid cHRM green point"); - png_crc_finish(png_ptr, 8); - return; - } + uint_x = png_get_uint_32(buf + 16); + uint_y = png_get_uint_32(buf + 20); int_x_green = (png_fixed_point)uint_x; int_y_green = (png_fixed_point)uint_y; - png_crc_read(png_ptr, buf, 4); - uint_x = png_get_uint_32(buf); - - png_crc_read(png_ptr, buf, 4); - uint_y = png_get_uint_32(buf); - - if (uint_x + uint_y > 100000L) - { - png_warning(png_ptr, "Invalid cHRM blue point"); - png_crc_finish(png_ptr, 0); - return; - } + uint_x = png_get_uint_32(buf + 24); + uint_y = png_get_uint_32(buf + 28); int_x_blue = (png_fixed_point)uint_x; int_y_blue = (png_fixed_point)uint_y; @@ -838,7 +880,7 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) blue_y = (float)int_y_blue / (float)100000.0; #endif -#if defined(PNG_READ_sRGB_SUPPORTED) +#ifdef PNG_READ_sRGB_SUPPORTED if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) { if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) || @@ -852,21 +894,22 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_CONSOLE_IO_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n", + fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n", white_x, white_y, red_x, red_y); - fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n", + fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n", green_x, green_y, blue_x, blue_y); #else - fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", - int_x_white, int_y_white, int_x_red, int_y_red); - fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n", - int_x_green, int_y_green, int_x_blue, int_y_blue); -#endif -#endif /* PNG_NO_CONSOLE_IO */ + fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + (long)int_x_white, (long)int_y_white, + (long)int_x_red, (long)int_y_red); + fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + (long)int_x_green, (long)int_y_green, + (long)int_x_blue, (long)int_y_blue); +#endif +#endif /* PNG_CONSOLE_IO_SUPPORTED */ } - png_crc_finish(png_ptr, 0); return; } #endif /* PNG_READ_sRGB_SUPPORTED */ @@ -880,19 +923,17 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, int_y_green, int_x_blue, int_y_blue); #endif - if (png_crc_finish(png_ptr, 0)) - return; } #endif -#if defined(PNG_READ_sRGB_SUPPORTED) +#ifdef PNG_READ_sRGB_SUPPORTED void /* PRIVATE */ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { int intent; png_byte buf[1]; - png_debug(1, "in png_handle_sRGB\n"); + png_debug(1, "in png_handle_sRGB"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before sRGB"); @@ -925,7 +966,7 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; intent = buf[0]; - /* check for bad intent */ + /* Check for bad intent */ if (intent >= PNG_sRGB_INTENT_LAST) { png_warning(png_ptr, "Unknown sRGB intent"); @@ -947,12 +988,13 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); -#ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_CONSOLE_IO_SUPPORTED # ifdef PNG_FIXED_POINT_SUPPORTED - fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma); + fprintf(stderr, "incorrect gamma=(%d/100000)\n", + (int)png_ptr->int_gamma); # else # ifdef PNG_FLOATING_POINT_SUPPORTED - fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma); + fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma); # endif # endif #endif @@ -982,12 +1024,11 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif /* PNG_READ_sRGB_SUPPORTED */ -#if defined(PNG_READ_iCCP_SUPPORTED) +#ifdef PNG_READ_iCCP_SUPPORTED void /* PRIVATE */ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_charp chunkdata; png_byte compression_type; png_bytep pC; png_charp profile; @@ -995,7 +1036,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_uint_32 profile_size, profile_length; png_size_t slength, prefix_length, data_length; - png_debug(1, "in png_handle_iCCP\n"); + png_debug(1, "in png_handle_iCCP"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before iCCP"); @@ -1025,93 +1066,129 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, skip)) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - chunkdata[slength] = 0x00; + png_ptr->chunkdata[slength] = 0x00; - for (profile = chunkdata; *profile; profile++) - /* empty loop to find end of name */ ; + for (profile = png_ptr->chunkdata; *profile; profile++) + /* Empty loop to find end of name */ ; ++profile; - /* there should be at least one zero (the compression type byte) - following the separator, and we should be on it */ - if ( profile >= chunkdata + slength - 1) + /* There should be at least one zero (the compression type byte) + * following the separator, and we should be on it + */ + if ( profile >= png_ptr->chunkdata + slength - 1) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_warning(png_ptr, "Malformed iCCP chunk"); return; } - /* compression_type should always be zero */ + /* Compression_type should always be zero */ compression_type = *profile++; if (compression_type) { png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); - compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 + compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 wrote nonzero) */ } - prefix_length = profile - chunkdata; - chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata, - slength, prefix_length, &data_length); + prefix_length = profile - png_ptr->chunkdata; + png_decompress_chunk(png_ptr, compression_type, + slength, prefix_length, &data_length); profile_length = data_length - prefix_length; if ( prefix_length > data_length || profile_length < 4) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_warning(png_ptr, "Profile size field missing from iCCP chunk"); return; } /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(chunkdata+prefix_length); - profile_size = ((*(pC ))<<24) | - ((*(pC+1))<<16) | - ((*(pC+2))<< 8) | - ((*(pC+3)) ); + pC = (png_bytep)(png_ptr->chunkdata + prefix_length); + profile_size = ((*(pC ))<<24) | + ((*(pC + 1))<<16) | + ((*(pC + 2))<< 8) | + ((*(pC + 3)) ); - if(profile_size < profile_length) + if (profile_size < profile_length) profile_length = profile_size; - if(profile_size > profile_length) + if (profile_size > profile_length) { - png_free(png_ptr, chunkdata); - png_warning(png_ptr, "Ignoring truncated iCCP profile."); +#ifdef PNG_STDIO_SUPPORTED + char umsg[50]; +#endif + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "Ignoring truncated iCCP profile"); +#ifdef PNG_STDIO_SUPPORTED + + png_snprintf(umsg, 50, "declared profile size = %lu", + (unsigned long)profile_size); + png_warning(png_ptr, umsg); + png_snprintf(umsg, 50, "actual profile length = %lu", + (unsigned long)profile_length); + png_warning(png_ptr, umsg); +#endif return; } - png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type, - chunkdata + prefix_length, profile_length); - png_free(png_ptr, chunkdata); + png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, + compression_type, png_ptr->chunkdata + prefix_length, profile_length); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; } #endif /* PNG_READ_iCCP_SUPPORTED */ -#if defined(PNG_READ_sPLT_SUPPORTED) +#ifdef PNG_READ_sPLT_SUPPORTED void /* PRIVATE */ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep chunkdata; png_bytep entry_start; png_sPLT_t new_palette; -#ifdef PNG_NO_POINTER_INDEXING +#ifdef PNG_POINTER_INDEXING_SUPPORTED png_sPLT_entryp pp; #endif int data_length, entry_size, i; png_uint_32 skip = 0; png_size_t slength; - png_debug(1, "in png_handle_sPLT\n"); + png_debug(1, "in png_handle_sPLT"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before sPLT"); @@ -1131,45 +1208,50 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - chunkdata = (png_bytep)png_malloc(png_ptr, length + 1); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, skip)) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - chunkdata[slength] = 0x00; + png_ptr->chunkdata[slength] = 0x00; - for (entry_start = chunkdata; *entry_start; entry_start++) - /* empty loop to find end of name */ ; + for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; + entry_start++) + /* Empty loop to find end of name */ ; ++entry_start; - /* a sample depth should follow the separator, and we should be on it */ - if (entry_start > chunkdata + slength - 2) + /* A sample depth should follow the separator, and we should be on it */ + if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_warning(png_ptr, "malformed sPLT chunk"); return; } new_palette.depth = *entry_start++; entry_size = (new_palette.depth == 8 ? 6 : 10); - data_length = (slength - (entry_start - chunkdata)); + data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata)); - /* integrity-check the data length */ + /* Integrity-check the data length */ if (data_length % entry_size) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_warning(png_ptr, "sPLT chunk has bad length"); return; } new_palette.nentries = (png_int_32) ( data_length / entry_size); - if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX / - png_sizeof(png_sPLT_entry))) + if ((png_uint_32) new_palette.nentries > + (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry))) { png_warning(png_ptr, "sPLT chunk too long"); return; @@ -1182,10 +1264,10 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } -#ifndef PNG_NO_POINTER_INDEXING +#ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0; i < new_palette.nentries; i++) { - png_sPLT_entryp pp = new_palette.entries + i; + pp = new_palette.entries + i; if (new_palette.depth == 8) { @@ -1226,29 +1308,24 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - /* discard all chunk data except the name and stash that */ - new_palette.name = (png_charp)chunkdata; + /* Discard all chunk data except the name and stash that */ + new_palette.name = png_ptr->chunkdata; png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_free(png_ptr, new_palette.entries); } #endif /* PNG_READ_sPLT_SUPPORTED */ -#if defined(PNG_READ_tRNS_SUPPORTED) +#ifdef PNG_READ_tRNS_SUPPORTED void /* PRIVATE */ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; - int bit_mask; - png_debug(1, "in png_handle_tRNS\n"); - - /* For non-indexed color, mask off any bits in the tRNS value that - * exceed the bit depth. Some creators were writing extra bits there. - * This is not needed for indexed color. */ - bit_mask = (1 << png_ptr->bit_depth) - 1; + png_debug(1, "in png_handle_tRNS"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before tRNS"); @@ -1278,7 +1355,7 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_read(png_ptr, buf, 2); png_ptr->num_trans = 1; - png_ptr->trans_values.gray = png_get_uint_16(buf) & bit_mask; + png_ptr->trans_color.gray = png_get_uint_16(buf); } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { @@ -1292,9 +1369,9 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, (png_size_t)length); png_ptr->num_trans = 1; - png_ptr->trans_values.red = png_get_uint_16(buf) & bit_mask; - png_ptr->trans_values.green = png_get_uint_16(buf + 2) & bit_mask; - png_ptr->trans_values.blue = png_get_uint_16(buf + 4) & bit_mask; + png_ptr->trans_color.red = png_get_uint_16(buf); + png_ptr->trans_color.green = png_get_uint_16(buf + 2); + png_ptr->trans_color.blue = png_get_uint_16(buf + 4); } else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -1333,18 +1410,18 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, - &(png_ptr->trans_values)); + &(png_ptr->trans_color)); } #endif -#if defined(PNG_READ_bKGD_SUPPORTED) +#ifdef PNG_READ_bKGD_SUPPORTED void /* PRIVATE */ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_size_t truelen; png_byte buf[6]; - png_debug(1, "in png_handle_bKGD\n"); + png_debug(1, "in png_handle_bKGD"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before bKGD"); @@ -1393,9 +1470,9 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { png_ptr->background.index = buf[0]; - if(info_ptr->num_palette) + if (info_ptr && info_ptr->num_palette) { - if(buf[0] > info_ptr->num_palette) + if (buf[0] >= info_ptr->num_palette) { png_warning(png_ptr, "Incorrect bKGD chunk index value"); return; @@ -1426,14 +1503,14 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_hIST_SUPPORTED) +#ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; - png_debug(1, "in png_handle_hIST\n"); + png_debug(1, "in png_handle_hIST"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before hIST"); @@ -1480,7 +1557,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_pHYs_SUPPORTED) +#ifdef PNG_READ_pHYs_SUPPORTED void /* PRIVATE */ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { @@ -1488,7 +1565,7 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_uint_32 res_x, res_y; int unit_type; - png_debug(1, "in png_handle_pHYs\n"); + png_debug(1, "in png_handle_pHYs"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before pHYs"); @@ -1523,7 +1600,7 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_oFFs_SUPPORTED) +#ifdef PNG_READ_oFFs_SUPPORTED void /* PRIVATE */ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { @@ -1531,7 +1608,7 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_int_32 offset_x, offset_y; int unit_type; - png_debug(1, "in png_handle_oFFs\n"); + png_debug(1, "in png_handle_oFFs"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before oFFs"); @@ -1566,12 +1643,11 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_pCAL_SUPPORTED) -/* read the pCAL chunk (described in the PNG Extensions document) */ +#ifdef PNG_READ_pCAL_SUPPORTED +/* Read the pCAL chunk (described in the PNG Extensions document) */ void /* PRIVATE */ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_charp purpose; png_int_32 X0, X1; png_byte type, nparams; png_charp buf, units, endptr; @@ -1579,7 +1655,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_size_t slength; int i; - png_debug(1, "in png_handle_pCAL\n"); + png_debug(1, "in png_handle_pCAL"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before pCAL"); @@ -1596,48 +1672,51 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n", + png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)", length + 1); - purpose = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (purpose == NULL) + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) { - png_warning(png_ptr, "No memory for pCAL purpose."); + png_warning(png_ptr, "No memory for pCAL purpose"); return; } slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)purpose, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, purpose); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - purpose[slength] = 0x00; /* null terminate the last string */ + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - png_debug(3, "Finding end of pCAL purpose string\n"); - for (buf = purpose; *buf; buf++) - /* empty loop */ ; + png_debug(3, "Finding end of pCAL purpose string"); + for (buf = png_ptr->chunkdata; *buf; buf++) + /* Empty loop */ ; - endptr = purpose + slength; + endptr = png_ptr->chunkdata + slength; /* We need to have at least 12 bytes after the purpose string in order to get the parameter information. */ if (endptr <= buf + 12) { png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, purpose); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n"); + png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); X0 = png_get_int_32((png_bytep)buf+1); X1 = png_get_int_32((png_bytep)buf+5); type = buf[9]; nparams = buf[10]; units = buf + 11; - png_debug(3, "Checking pCAL equation type and number of parameters\n"); + png_debug(3, "Checking pCAL equation type and number of parameters"); /* Check that we have the right number of parameters for known equation types. */ if ((type == PNG_EQUATION_LINEAR && nparams != 2) || @@ -1646,7 +1725,8 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) { png_warning(png_ptr, "Invalid pCAL parameters for equation type"); - png_free(png_ptr, purpose); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } else if (type >= PNG_EQUATION_LAST) @@ -1657,13 +1737,14 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) for (buf = units; *buf; buf++) /* Empty loop to move past the units string. */ ; - png_debug(3, "Allocating pCAL parameters array\n"); - params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams - *png_sizeof(png_charp))) ; + png_debug(3, "Allocating pCAL parameters array"); + params = (png_charpp)png_malloc_warn(png_ptr, + (png_size_t)(nparams * png_sizeof(png_charp))); if (params == NULL) { - png_free(png_ptr, purpose); - png_warning(png_ptr, "No memory for pCAL params."); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_warning(png_ptr, "No memory for pCAL params"); return; } @@ -1672,34 +1753,36 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { buf++; /* Skip the null string terminator from previous parameter. */ - png_debug1(3, "Reading pCAL parameter %d\n", i); - for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++) + png_debug1(3, "Reading pCAL parameter %d", i); + for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) /* Empty loop to move past each parameter string */ ; /* Make sure we haven't run out of data yet */ if (buf > endptr) { png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, purpose); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_free(png_ptr, params); return; } } - png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams, + png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, units, params); - png_free(png_ptr, purpose); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_free(png_ptr, params); } #endif -#if defined(PNG_READ_sCAL_SUPPORTED) -/* read the sCAL chunk */ +#ifdef PNG_READ_sCAL_SUPPORTED +/* Read the sCAL chunk */ void /* PRIVATE */ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_charp buffer, ep; + png_charp ep; #ifdef PNG_FLOATING_POINT_SUPPORTED double width, height; png_charp vp; @@ -1710,7 +1793,7 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #endif png_size_t slength; - png_debug(1, "in png_handle_sCAL\n"); + png_debug(1, "in png_handle_sCAL"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before sCAL"); @@ -1727,77 +1810,100 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n", + png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)", length + 1); - buffer = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (buffer == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); - return; - } + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)buffer, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, buffer); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - buffer[slength] = 0x00; /* null terminate the last string */ + png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - ep = buffer + 1; /* skip unit byte */ + ep = png_ptr->chunkdata + 1; /* Skip unit byte */ #ifdef PNG_FLOATING_POINT_SUPPORTED width = png_strtod(png_ptr, ep, &vp); if (*vp) { - png_warning(png_ptr, "malformed width string in sCAL chunk"); - return; + png_warning(png_ptr, "malformed width string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; } #else #ifdef PNG_FIXED_POINT_SUPPORTED swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); if (swidth == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); - return; - } - png_memcpy(swidth, ep, (png_size_t)png_strlen(ep)); + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk width"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + png_memcpy(swidth, ep, png_strlen(ep)); #endif #endif - for (ep = buffer; *ep; ep++) - /* empty loop */ ; + for (ep = png_ptr->chunkdata; *ep; ep++) + /* Empty loop */ ; ep++; + if (png_ptr->chunkdata + slength < ep) + { + png_warning(png_ptr, "Truncated sCAL chunk"); +#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); +#endif + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } + #ifdef PNG_FLOATING_POINT_SUPPORTED height = png_strtod(png_ptr, ep, &vp); if (*vp) { - png_warning(png_ptr, "malformed height string in sCAL chunk"); - return; + png_warning(png_ptr, "malformed height string in sCAL chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; } #else #ifdef PNG_FIXED_POINT_SUPPORTED sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1); - if (swidth == NULL) - { - png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); - return; - } - png_memcpy(sheight, ep, (png_size_t)png_strlen(ep)); + if (sheight == NULL) + { + png_warning(png_ptr, "Out of memory while processing sCAL chunk height"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + png_free(png_ptr, swidth); + return; + } + png_memcpy(sheight, ep, png_strlen(ep)); #endif #endif - if (buffer + slength < ep + if (png_ptr->chunkdata + slength < ep #ifdef PNG_FLOATING_POINT_SUPPORTED || width <= 0. || height <= 0. #endif ) { png_warning(png_ptr, "Invalid sCAL data"); - png_free(png_ptr, buffer); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; #if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) png_free(png_ptr, swidth); png_free(png_ptr, sheight); @@ -1807,14 +1913,15 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #ifdef PNG_FLOATING_POINT_SUPPORTED - png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height); + png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height); #else #ifdef PNG_FIXED_POINT_SUPPORTED - png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight); + png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight); #endif #endif - png_free(png_ptr, buffer); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; #if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) png_free(png_ptr, swidth); png_free(png_ptr, sheight); @@ -1822,14 +1929,14 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_tIME_SUPPORTED) +#ifdef PNG_READ_tIME_SUPPORTED void /* PRIVATE */ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_byte buf[7]; png_time mod_time; - png_debug(1, "in png_handle_tIME\n"); + png_debug(1, "in png_handle_tIME"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Out of place tIME chunk"); @@ -1865,7 +1972,7 @@ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif -#if defined(PNG_READ_tEXt_SUPPORTED) +#ifdef PNG_READ_tEXt_SUPPORTED /* Note: this does not properly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) @@ -1877,7 +1984,24 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_size_t slength; int ret; - png_debug(1, "in png_handle_tEXt\n"); + png_debug(1, "in png_handle_tEXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for tEXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before tEXt"); @@ -1894,35 +2018,41 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - key = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (key == NULL) + png_free(png_ptr, png_ptr->chunkdata); + + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) { - png_warning(png_ptr, "No memory to process text chunk."); + png_warning(png_ptr, "No memory to process text chunk"); return; } slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)key, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, skip)) { - png_free(png_ptr, key); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } + key = png_ptr->chunkdata; + key[slength] = 0x00; for (text = key; *text; text++) - /* empty loop to find end of key */ ; + /* Empty loop to find end of key */ ; if (text != key + slength) text++; text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); + png_sizeof(png_text)); if (text_ptr == NULL) { - png_warning(png_ptr, "Not enough memory to process text chunk."); - png_free(png_ptr, key); + png_warning(png_ptr, "Not enough memory to process text chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; @@ -1935,28 +2065,46 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) text_ptr->text = text; text_ptr->text_length = png_strlen(text); - ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - png_free(png_ptr, key); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; png_free(png_ptr, text_ptr); if (ret) - png_warning(png_ptr, "Insufficient memory to process text chunk."); + png_warning(png_ptr, "Insufficient memory to process text chunk"); } #endif -#if defined(PNG_READ_zTXt_SUPPORTED) -/* note: this does not correctly handle chunks that are > 64K under DOS */ +#ifdef PNG_READ_zTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_textp text_ptr; - png_charp chunkdata; png_charp text; int comp_type; int ret; png_size_t slength, prefix_len, data_len; - png_debug(1, "in png_handle_zTXt\n"); + png_debug(1, "in png_handle_zTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for zTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif + if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before zTXt"); @@ -1968,36 +2116,39 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) there is no hard and fast rule to tell us where to stop. */ if (length > (png_uint_32)65535L) { - png_warning(png_ptr,"zTXt chunk too large to fit in memory"); + png_warning(png_ptr, "zTXt chunk too large to fit in memory"); png_crc_finish(png_ptr, length); return; } #endif - chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (chunkdata == NULL) + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) { - png_warning(png_ptr,"Out of memory processing zTXt chunk."); + png_warning(png_ptr, "Out of memory processing zTXt chunk"); return; } slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - chunkdata[slength] = 0x00; + png_ptr->chunkdata[slength] = 0x00; - for (text = chunkdata; *text; text++) - /* empty loop */ ; + for (text = png_ptr->chunkdata; *text; text++) + /* Empty loop */ ; /* zTXt must have some text after the chunkdataword */ - if (text == chunkdata + slength - 1) + if (text >= png_ptr->chunkdata + slength - 2) { png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } else @@ -2008,54 +2159,72 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_warning(png_ptr, "Unknown compression type in zTXt chunk"); comp_type = PNG_TEXT_COMPRESSION_zTXt; } - text++; /* skip the compression_method byte */ + text++; /* Skip the compression_method byte */ } - prefix_len = text - chunkdata; + prefix_len = text - png_ptr->chunkdata; - chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata, - (png_size_t)length, prefix_len, &data_len); + png_decompress_chunk(png_ptr, comp_type, + (png_size_t)length, prefix_len, &data_len); text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); + png_sizeof(png_text)); if (text_ptr == NULL) { - png_warning(png_ptr,"Not enough memory to process zTXt chunk."); - png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Not enough memory to process zTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } text_ptr->compression = comp_type; - text_ptr->key = chunkdata; + text_ptr->key = png_ptr->chunkdata; #ifdef PNG_iTXt_SUPPORTED text_ptr->lang = NULL; text_ptr->lang_key = NULL; text_ptr->itxt_length = 0; #endif - text_ptr->text = chunkdata + prefix_len; + text_ptr->text = png_ptr->chunkdata + prefix_len; text_ptr->text_length = data_len; - ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); png_free(png_ptr, text_ptr); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk."); + png_error(png_ptr, "Insufficient memory to store zTXt chunk"); } #endif -#if defined(PNG_READ_iTXt_SUPPORTED) -/* note: this does not correctly handle chunks that are > 64K under DOS */ +#ifdef PNG_READ_iTXt_SUPPORTED +/* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_textp text_ptr; - png_charp chunkdata; png_charp key, lang, text, lang_key; int comp_flag; int comp_type = 0; int ret; png_size_t slength, prefix_len, data_len; - png_debug(1, "in png_handle_iTXt\n"); + png_debug(1, "in png_handle_iTXt"); + +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for iTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before iTXt"); @@ -2068,40 +2237,44 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) there is no hard and fast rule to tell us where to stop. */ if (length > (png_uint_32)65535L) { - png_warning(png_ptr,"iTXt chunk too large to fit in memory"); + png_warning(png_ptr, "iTXt chunk too large to fit in memory"); png_crc_finish(png_ptr, length); return; } #endif - chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - if (chunkdata == NULL) + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); + if (png_ptr->chunkdata == NULL) { - png_warning(png_ptr, "No memory to process iTXt chunk."); + png_warning(png_ptr, "No memory to process iTXt chunk"); return; } slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - chunkdata[slength] = 0x00; + png_ptr->chunkdata[slength] = 0x00; - for (lang = chunkdata; *lang; lang++) - /* empty loop */ ; - lang++; /* skip NUL separator */ + for (lang = png_ptr->chunkdata; *lang; lang++) + /* Empty loop */ ; + lang++; /* Skip NUL separator */ /* iTXt must have a language tag (possibly empty), two compression bytes, - translated keyword (possibly empty), and possibly some text after the - keyword */ + * translated keyword (possibly empty), and possibly some text after the + * keyword + */ - if (lang >= chunkdata + slength - 3) + if (lang >= png_ptr->chunkdata + slength - 3) { png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } else @@ -2111,49 +2284,60 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } for (lang_key = lang; *lang_key; lang_key++) - /* empty loop */ ; - lang_key++; /* skip NUL separator */ + /* Empty loop */ ; + lang_key++; /* Skip NUL separator */ + + if (lang_key >= png_ptr->chunkdata + slength) + { + png_warning(png_ptr, "Truncated iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; + return; + } for (text = lang_key; *text; text++) - /* empty loop */ ; - text++; /* skip NUL separator */ - if (text >= chunkdata + slength) + /* Empty loop */ ; + text++; /* Skip NUL separator */ + if (text >= png_ptr->chunkdata + slength) { png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } - prefix_len = text - chunkdata; + prefix_len = text - png_ptr->chunkdata; - key=chunkdata; + key=png_ptr->chunkdata; if (comp_flag) - chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata, - (size_t)length, prefix_len, &data_len); + png_decompress_chunk(png_ptr, comp_type, + (size_t)length, prefix_len, &data_len); else - data_len=png_strlen(chunkdata + prefix_len); + data_len = png_strlen(png_ptr->chunkdata + prefix_len); text_ptr = (png_textp)png_malloc_warn(png_ptr, - (png_uint_32)png_sizeof(png_text)); + png_sizeof(png_text)); if (text_ptr == NULL) { - png_warning(png_ptr,"Not enough memory to process iTXt chunk."); - png_free(png_ptr, chunkdata); + png_warning(png_ptr, "Not enough memory to process iTXt chunk"); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; return; } text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = chunkdata+(lang_key-key); - text_ptr->lang = chunkdata+(lang-key); + text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); + text_ptr->lang = png_ptr->chunkdata + (lang - key); text_ptr->itxt_length = data_len; text_ptr->text_length = 0; - text_ptr->key = chunkdata; - text_ptr->text = chunkdata + prefix_len; + text_ptr->key = png_ptr->chunkdata; + text_ptr->text = png_ptr->chunkdata + prefix_len; - ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1); + ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); png_free(png_ptr, text_ptr); - png_free(png_ptr, chunkdata); + png_free(png_ptr, png_ptr->chunkdata); + png_ptr->chunkdata = NULL; if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk."); + png_error(png_ptr, "Insufficient memory to store iTXt chunk"); } #endif @@ -2167,25 +2351,38 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_uint_32 skip = 0; - png_debug(1, "in png_handle_unknown\n"); + png_debug(1, "in png_handle_unknown"); - if (png_ptr->mode & PNG_HAVE_IDAT) +#ifdef PNG_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for unknown chunk"); + png_crc_finish(png_ptr, length); + return; + } + } #endif - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */ + + if (png_ptr->mode & PNG_HAVE_IDAT) + { + PNG_IDAT; + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ png_ptr->mode |= PNG_AFTER_IDAT; } - png_check_chunk_name(png_ptr, png_ptr->chunk_name); - if (!(png_ptr->chunk_name[0] & 0x20)) { -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != PNG_HANDLE_CHUNK_ALWAYS -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED && png_ptr->read_user_chunk_fn == NULL #endif ) @@ -2193,9 +2390,12 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_chunk_error(png_ptr, "unknown critical chunk"); } -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) || - (png_ptr->read_user_chunk_fn != NULL)) +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + || (png_ptr->read_user_chunk_fn != NULL) +#endif + ) { #ifdef PNG_MAX_MALLOC_64K if (length > (png_uint_32)65535L) @@ -2205,16 +2405,23 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) length = (png_uint_32)65535L; } #endif - png_strncpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof((png_charp)png_ptr->chunk_name)); - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_memcpy((png_charp)png_ptr->unknown_chunk.name, + (png_charp)png_ptr->chunk_name, + png_sizeof(png_ptr->unknown_chunk.name)); + png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] + = '\0'; png_ptr->unknown_chunk.size = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); -#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) - if(png_ptr->read_user_chunk_fn != NULL) + if (length == 0) + png_ptr->unknown_chunk.data = NULL; + else { - /* callback to user unknown chunk handler */ + png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); + } +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + if (png_ptr->read_user_chunk_fn != NULL) + { + /* Callback to user unknown chunk handler */ int ret; ret = (*(png_ptr->read_user_chunk_fn)) (png_ptr, &png_ptr->unknown_chunk); @@ -2223,16 +2430,18 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (ret == 0) { if (!(png_ptr->chunk_name[0] & 0x20)) - if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED + if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != PNG_HANDLE_CHUNK_ALWAYS) +#endif png_chunk_error(png_ptr, "unknown critical chunk"); png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); } } -#else - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); + else #endif + png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); png_free(png_ptr, png_ptr->unknown_chunk.data); png_ptr->unknown_chunk.data = NULL; } @@ -2242,8 +2451,8 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_crc_finish(png_ptr, skip); -#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED) - info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */ +#ifndef PNG_READ_USER_CHUNKS_SUPPORTED + info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */ #endif } @@ -2258,7 +2467,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void /* PRIVATE */ png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) { - png_debug(1, "in png_check_chunk_name\n"); + png_debug(1, "in png_check_chunk_name"); if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) { @@ -2280,7 +2489,7 @@ png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name) void /* PRIVATE */ png_combine_row(png_structp png_ptr, png_bytep row, int mask) { - png_debug(1,"in png_combine_row\n"); + png_debug(1, "in png_combine_row"); if (mask == 0xff) { png_memcpy(row, png_ptr->row_buf + 1, @@ -2300,7 +2509,7 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) png_uint_32 i; png_uint_32 row_width = png_ptr->width; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (png_ptr->transformations & PNG_PACKSWAP) { s_start = 0; @@ -2355,7 +2564,7 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) png_uint_32 row_width = png_ptr->width; int value; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (png_ptr->transformations & PNG_PACKSWAP) { s_start = 0; @@ -2407,7 +2616,7 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) png_uint_32 row_width = png_ptr->width; int value; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (png_ptr->transformations & PNG_PACKSWAP) { s_start = 0; @@ -2490,13 +2699,11 @@ png_do_read_interlace(png_structp png_ptr) png_bytep row = png_ptr->row_buf + 1; int pass = png_ptr->pass; png_uint_32 transformations = png_ptr->transformations; -#ifdef PNG_USE_LOCAL_ARRAYS - /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* offset to next interlace block */ + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; -#endif - png_debug(1,"in png_do_read_interlace\n"); + png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) { png_uint_32 final_width; @@ -2516,7 +2723,7 @@ png_do_read_interlace(png_structp png_ptr) png_uint_32 i; int j; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)((row_info->width + 7) & 0x07); @@ -2569,7 +2776,7 @@ png_do_read_interlace(png_structp png_ptr) int jstop = png_pass_inc[pass]; png_uint_32 i; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)(((row_info->width + 3) & 0x03) << 1); @@ -2625,7 +2832,7 @@ png_do_read_interlace(png_structp png_ptr) png_uint_32 i; int jstop = png_pass_inc[pass]; -#if defined(PNG_READ_PACKSWAP_SUPPORTED) +#ifdef PNG_READ_PACKSWAP_SUPPORTED if (transformations & PNG_PACKSWAP) { sshift = (int)(((row_info->width + 1) & 0x01) << 2); @@ -2674,7 +2881,8 @@ png_do_read_interlace(png_structp png_ptr) default: { png_size_t pixel_bytes = (row_info->pixel_depth >> 3); - png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; + png_bytep sp = row + (png_size_t)(row_info->width - 1) + * pixel_bytes; png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; int jstop = png_pass_inc[pass]; @@ -2697,10 +2905,10 @@ png_do_read_interlace(png_structp png_ptr) } } row_info->width = final_width; - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); } -#if !defined(PNG_READ_PACKSWAP_SUPPORTED) - transformations = transformations; /* silence compiler warning */ +#ifndef PNG_READ_PACKSWAP_SUPPORTED + transformations = transformations; /* Silence compiler warning */ #endif } #endif /* PNG_READ_INTERLACING_SUPPORTED */ @@ -2709,8 +2917,8 @@ void /* PRIVATE */ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter) { - png_debug(1, "in png_read_filter_row\n"); - png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter); + png_debug(1, "in png_read_filter_row"); + png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter); switch (filter) { case PNG_FILTER_VALUE_NONE: @@ -2784,7 +2992,7 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, rp++; } - for (i = 0; i < istop; i++) /* use leftover rp,pp */ + for (i = 0; i < istop; i++) /* Use leftover rp,pp */ { int a, b, c, pa, pb, pc, p; @@ -2814,7 +3022,7 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, p = c; */ - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; *rp = (png_byte)(((int)(*rp) + p) & 0xff); rp++; @@ -2823,39 +3031,41 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, } default: png_warning(png_ptr, "Ignoring bad adaptive filter type"); - *row=0; + *row = 0; break; } } +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ png_read_finish_row(png_structp png_ptr) { -#ifdef PNG_USE_LOCAL_ARRAYS - /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* start of interlace block */ + /* Start of interlace block */ PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - /* offset to next interlace block */ + /* Offset to next interlace block */ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - /* start of interlace block in the y direction */ + /* Start of interlace block in the y direction */ PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - /* offset to next interlace block in the y direction */ + /* Offset to next interlace block in the y direction */ PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif +#endif /* PNG_READ_INTERLACING_SUPPORTED */ - png_debug(1, "in png_read_finish_row\n"); + png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; +#ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced) { png_ptr->row_number = 0; - png_memset_check(png_ptr, png_ptr->prev_row, 0, + png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { @@ -2867,9 +3077,6 @@ png_read_finish_row(png_structp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, - png_ptr->iwidth) + 1; - if (!(png_ptr->transformations & PNG_INTERLACE)) { png_ptr->num_rows = (png_ptr->height + @@ -2886,18 +3093,17 @@ png_read_finish_row(png_structp png_ptr) if (png_ptr->pass < 7) return; } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) { -#ifdef PNG_USE_LOCAL_ARRAYS - PNG_CONST PNG_IDAT; -#endif + PNG_IDAT; char extra; int ret; png_ptr->zstream.next_out = (Byte *)&extra; png_ptr->zstream.avail_out = (uInt)1; - for(;;) + for (;;) { if (!(png_ptr->zstream.avail_in)) { @@ -2911,7 +3117,7 @@ png_read_finish_row(png_structp png_ptr) png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); - if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4)) + if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) png_error(png_ptr, "Not enough image data"); } @@ -2938,7 +3144,7 @@ png_read_finish_row(png_structp png_ptr) if (!(png_ptr->zstream.avail_out)) { - png_warning(png_ptr, "Extra compressed data."); + png_warning(png_ptr, "Extra compressed data"); png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; @@ -2955,32 +3161,34 @@ png_read_finish_row(png_structp png_ptr) png_ptr->mode |= PNG_AFTER_IDAT; } +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ void /* PRIVATE */ png_read_start_row(png_structp png_ptr) { -#ifdef PNG_USE_LOCAL_ARRAYS - /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - /* start of interlace block */ + /* Start of interlace block */ PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - /* offset to next interlace block */ + /* Offset to next interlace block */ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - /* start of interlace block in the y direction */ + /* Start of interlace block in the y direction */ PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - /* offset to next interlace block in the y direction */ + /* Offset to next interlace block in the y direction */ PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif int max_pixel_depth; - png_uint_32 row_bytes; + png_size_t row_bytes; - png_debug(1, "in png_read_start_row\n"); + png_debug(1, "in png_read_start_row"); png_ptr->zstream.avail_in = 0; png_init_read_transformations(png_ptr); +#ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced) { if (!(png_ptr->transformations & PNG_INTERLACE)) @@ -2993,27 +3201,21 @@ png_read_start_row(png_structp png_ptr) png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - - row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1; - - png_ptr->irowbytes = (png_size_t)row_bytes; - if((png_uint_32)png_ptr->irowbytes != row_bytes) - png_error(png_ptr, "Rowbytes overflow in png_read_start_row"); } else +#endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; - png_ptr->irowbytes = png_ptr->rowbytes + 1; } max_pixel_depth = png_ptr->pixel_depth; -#if defined(PNG_READ_PACK_SUPPORTED) +#ifdef PNG_READ_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif -#if defined(PNG_READ_EXPAND_SUPPORTED) +#ifdef PNG_READ_EXPAND_SUPPORTED if (png_ptr->transformations & PNG_EXPAND) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) @@ -3041,7 +3243,7 @@ png_read_start_row(png_structp png_ptr) } #endif -#if defined(PNG_READ_FILLER_SUPPORTED) +#ifdef PNG_READ_FILLER_SUPPORTED if (png_ptr->transformations & (PNG_FILLER)) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) @@ -3063,14 +3265,14 @@ png_read_start_row(png_structp png_ptr) } #endif -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if (png_ptr->transformations & PNG_GRAY_TO_RGB) { if ( -#if defined(PNG_READ_EXPAND_SUPPORTED) +#ifdef PNG_READ_EXPAND_SUPPORTED (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || #endif -#if defined(PNG_READ_FILLER_SUPPORTED) +#ifdef PNG_READ_FILLER_SUPPORTED (png_ptr->transformations & (PNG_FILLER)) || #endif png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -3099,46 +3301,78 @@ png_read_start_row(png_structp png_ptr) #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if(png_ptr->transformations & PNG_USER_TRANSFORM) + if (png_ptr->transformations & PNG_USER_TRANSFORM) { - int user_pixel_depth=png_ptr->user_transform_depth* + int user_pixel_depth = png_ptr->user_transform_depth* png_ptr->user_transform_channels; - if(user_pixel_depth > max_pixel_depth) + if (user_pixel_depth > max_pixel_depth) max_pixel_depth=user_pixel_depth; } #endif - /* align the width on the next larger 8 pixels. Mainly used - for interlacing */ + /* Align the width on the next larger 8 pixels. Mainly used + * for interlacing + */ row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); - /* calculate the maximum bytes needed, adding a byte and a pixel - for safety's sake */ - row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) + + /* Calculate the maximum bytes needed, adding a byte and a pixel + * for safety's sake + */ + row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + 1 + ((max_pixel_depth + 7) >> 3); #ifdef PNG_MAX_MALLOC_64K if (row_bytes > (png_uint_32)65536L) png_error(png_ptr, "This image requires a row greater than 64KB"); #endif - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64); - png_ptr->row_buf = png_ptr->big_row_buf+32; + + if (row_bytes + 48 > png_ptr->old_big_row_buf_size) + { + png_free(png_ptr, png_ptr->big_row_buf); + if (png_ptr->interlaced) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, + row_bytes + 48); + png_ptr->old_big_row_buf_size = row_bytes + 48; + +#ifdef PNG_ALIGNED_MEMORY_SUPPORTED + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf. + */ + png_ptr->row_buf = png_ptr->big_row_buf + 32 + - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16); + png_ptr->old_big_row_buf_size = row_bytes + 48; +#else + /* Use 32 bytes of padding before and 16 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 32; +#endif + png_ptr->old_big_row_buf_size = row_bytes + 48; + } #ifdef PNG_MAX_MALLOC_64K if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L) png_error(png_ptr, "This image requires a row greater than 64KB"); #endif if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1)) - png_error(png_ptr, "Row has too many bytes to allocate in memory."); - png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( - png_ptr->rowbytes + 1)); - - png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1); - - png_debug1(3, "width = %lu,\n", png_ptr->width); - png_debug1(3, "height = %lu,\n", png_ptr->height); - png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth); - png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows); - png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes); - png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes); + png_error(png_ptr, "Row has too many bytes to allocate in memory"); + + if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size) + { + png_free(png_ptr, png_ptr->prev_row); + png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)( + png_ptr->rowbytes + 1)); + png_ptr->old_prev_row_size = png_ptr->rowbytes + 1; + } + + png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + + png_debug1(3, "width = %lu,", png_ptr->width); + png_debug1(3, "height = %lu,", png_ptr->height); + png_debug1(3, "iwidth = %lu,", png_ptr->iwidth); + png_debug1(3, "num_rows = %lu,", png_ptr->num_rows); + png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes); + png_debug1(3, "irowbytes = %lu", + PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); png_ptr->flags |= PNG_FLAG_ROW_INIT; }