[legacy] Ported png_decompress_chunk() from libpng-1.4.1

This commit is contained in:
Glenn Randers-Pehrson 2010-02-12 21:05:33 -06:00
parent 8c061f646c
commit 05a22295f2
3 changed files with 185 additions and 216 deletions

View File

@ -1,5 +1,5 @@
Libpng 1.2.43beta04 - February 9, 2010 Libpng 1.2.43beta05 - February 13, 2010
This is not intended to be a public release. It will be replaced This is not intended to be a public release. It will be replaced
within a few weeks by a public version or by another test version. within a few weeks by a public version or by another test version.
@ -9,36 +9,36 @@ Files available for download:
Source files with LF line endings (for Unix/Linux) and with a Source files with LF line endings (for Unix/Linux) and with a
"configure" script "configure" script
libpng-1.2.43beta04.tar.xz (LZMA-compressed, recommended) libpng-1.2.43beta05.tar.xz (LZMA-compressed, recommended)
libpng-1.2.43beta04.tar.gz libpng-1.2.43beta05.tar.gz
libpng-1.2.43beta04.tar.bz2 libpng-1.2.43beta05.tar.bz2
Source files with LF line endings (for Unix/Linux) without the Source files with LF line endings (for Unix/Linux) without the
"configure" script "configure" script
libpng-1.2.43beta04-no-config.tar.xz (LZMA-compressed, recommended) libpng-1.2.43beta05-no-config.tar.xz (LZMA-compressed, recommended)
libpng-1.2.43beta04-no-config.tar.gz libpng-1.2.43beta05-no-config.tar.gz
libpng-1.2.43beta04-no-config.tar.bz2 libpng-1.2.43beta05-no-config.tar.bz2
Source files with CRLF line endings (for Windows), without the Source files with CRLF line endings (for Windows), without the
"configure" script "configure" script
lp1243b04.zip lp1243b05.zip
lp1243b04.7z lp1243b05.7z
lp1243b04.tar.bz2 lp1243b05.tar.bz2
Project files Project files
libpng-1.2.43beta04-project-netware.zip libpng-1.2.43beta05-project-netware.zip
libpng-1.2.43beta04-project-wince.zip libpng-1.2.43beta05-project-wince.zip
Other information: Other information:
libpng-1.2.43beta04-README.txt libpng-1.2.43beta05-README.txt
libpng-1.2.43beta04-KNOWNBUGS.txt libpng-1.2.43beta05-KNOWNBUGS.txt
libpng-1.2.43beta04-LICENSE.txt libpng-1.2.43beta05-LICENSE.txt
libpng-1.2.43beta04-Y2K-compliance.txt libpng-1.2.43beta05-Y2K-compliance.txt
libpng-1.2.43beta04-[previous version]-diff.txt libpng-1.2.43beta05-[previous version]-diff.txt
Changes since the last public release (1.2.42): Changes since the last public release (1.2.42):
@ -58,13 +58,16 @@ version 1.2.43beta03 [February 6, 2010]
Backported fast png_push_save_buffer() algorithm from libpng-1.4.1 Backported fast png_push_save_buffer() algorithm from libpng-1.4.1
version 1.2.43beta04 [February 8, 2010] version 1.2.43beta04 [February 8, 2010]
Fixed incorrect test in new png_push_save_buffer() code.
Reverted recent changes to png_push_save-buffer(). Reverted recent changes to png_push_save-buffer().
Removed PNGAPI declaration of png_calloc() and png_write_sig() in Removed PNGAPI declaration of png_calloc() and png_write_sig() in
1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41.
Return allocated "old_buffer" in png_push_save_buffer() before png_error(). Return allocated "old_buffer" in png_push_save_buffer() before png_error(),
to avoid a potential memory leak.
version 1.0.53rc01 and 1.2.43rc01 [February 9, 2010] version 1.2.43beta05 [February 8, 2010]
Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1.
version 1.0.53rc01 and 1.2.43rc01 [February 13, 2010]
No changes. No changes.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net

View File

@ -2660,13 +2660,16 @@ version 1.2.43beta03 [February 6, 2010]
Backported some cosmetic changes from libpng-1.4.1. Backported some cosmetic changes from libpng-1.4.1.
version 1.2.43beta04 [February 8, 2010] version 1.2.43beta04 [February 8, 2010]
Fixed incorrect test in new png_push_save_buffer() code.
Reverted recent changes to png_push_save-buffer(). Reverted recent changes to png_push_save-buffer().
Removed PNGAPI declaration of png_calloc() and png_write_sig() in Removed PNGAPI declaration of png_calloc() and png_write_sig() in
1ibpng-1.2.X, introduced by mistake in libpng-1.2.41. 1ibpng-1.2.X, introduced by mistake in libpng-1.2.41.
Return allocated "old_buffer" in png_push_save_buffer() before png_error(). Return allocated "old_buffer" in png_push_save_buffer() before png_error()
to avoid a potential memory leak.
version 1.0.53rc01 and 1.2.43rc01 [February 9, 2010] version 1.2.43beta05 [February 8, 2010]
Ported rewritten png_decompress_chunk() by John Bowler from libpng-1.4.1.
version 1.0.53rc01 and 1.2.43rc01 [February 13, 2010]
No changes. No changes.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net Send comments/corrections/commendations to png-mng-implement at lists.sf.net

View File

@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file /* pngrutil.c - utilities to read a PNG file
* *
* Last changed in libpng 1.2.43 [February 9, 2010] * Last changed in libpng 1.2.43 [February 13, 2010]
* Copyright (c) 1998-2009 Glenn Randers-Pehrson * Copyright (c) 1998-2009 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@ -218,70 +218,93 @@ png_crc_error(png_structp png_ptr)
#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ #if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
defined(PNG_READ_iCCP_SUPPORTED) defined(PNG_READ_iCCP_SUPPORTED)
png_size_t static png_size_t
png_measure_decompressed_chunk(png_structp png_ptr, int comp_type, png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size,
png_size_t chunklength, png_size_t prefix_size) png_bytep output, png_size_t output_size)
{ {
png_charp text; png_size_t count = 0;
png_charp test = "X";
png_size_t text_size = 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; int ret, avail;
png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size); /* Reset the output buffer each time round - we empty it
png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); * after every inflate call.
*/
png_ptr->zstream.next_out = png_ptr->zbuf; 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 = 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 (output != 0 && output_size > count)
if (ret != Z_OK && ret != Z_STREAM_END) {
{ int copy = output_size - count;
inflateReset(&png_ptr->zstream); if (avail < copy) copy = avail;
png_ptr->zstream.avail_in = 0; png_memcpy(output + count, png_ptr->zbuf, copy);
break; }
} count += avail;
if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
{
if (text == NULL) /* Initialize the decompression buffer */
{
text_size = prefix_size +
png_ptr->zbuf_size - png_ptr->zstream.avail_out;
text=test;
}
else /* Enlarge the decompression buffer */
{
text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
if (png_ptr->user_chunk_malloc_max &&
(text_size >= png_ptr->user_chunk_malloc_max - 1))
#else
if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
text_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
#endif
return 0;
}
}
if (ret == Z_STREAM_END)
break;
else
{
png_ptr->zstream.next_out = png_ptr->zbuf;
png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
}
} }
inflateReset(&png_ptr->zstream); if (ret == Z_OK)
continue;
/* Termination conditions - always reset the zstream, it
* must be left in inflateInit state.
*/
png_ptr->zstream.avail_in = 0; png_ptr->zstream.avail_in = 0;
inflateReset(&png_ptr->zstream);
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.
*/
{
char *msg, umsg[52];
if (png_ptr->zstream.msg != 0)
msg = png_ptr->zstream.msg;
else
{
#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
switch (ret)
{
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);
}
/* 0 means an error - notice that this code simple ignores
* zero length compressed chunks as a result.
*/
return 0;
} }
return text_size;
} }
/* /*
@ -296,164 +319,104 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
png_size_t chunklength, png_size_t chunklength,
png_size_t prefix_size, png_size_t *newlength) png_size_t prefix_size, png_size_t *newlength)
{ {
static PNG_CONST char msg[] = "Error decoding compressed chunk"; /* The caller should guarantee this */
png_charp text; if (prefix_size > chunklength)
png_size_t text_size;
png_size_t expanded_size;
expanded_size= png_measure_decompressed_chunk(png_ptr, comp_type,
chunklength, prefix_size);
if (expanded_size == 0)
{ {
*newlength=0; /* The recovery is to delete the chunk. */
return; png_warning(png_ptr, "invalid chunklength");
prefix_size = 0; /* To delete everything */
} }
if (comp_type == PNG_COMPRESSION_TYPE_BASE) else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
{ {
int ret = Z_OK; png_size_t expanded_size = png_inflate(png_ptr,
png_size_t buffer_size; (png_bytep)(png_ptr->chunkdata + prefix_size),
chunklength - prefix_size,
0/*output*/, 0/*output size*/);
png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size); /* Now check the limits on this chunk - if the limit fails the
png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); * compressed data will be removed, the prefix will remain.
png_ptr->zstream.next_out = png_ptr->zbuf; */
png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; #ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
if (png_ptr->user_chunk_malloc_max &&
text_size = 0; (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
text = NULL;
buffer_size = 0;
while (png_ptr->zstream.avail_in)
{
ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
{
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;
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_error(png_ptr,
"Not enough memory to decompress chunk");
text_size = 0;
break;
}
png_memcpy(text, png_ptr->chunkdata, prefix_size);
}
text[text_size - 1] = 0x00;
/* Copy what we can of the error message into the text chunk */
text_size = (png_size_t)(chunklength -
(text - png_ptr->chunkdata) - 1);
if (text_size > png_sizeof(msg))
text_size = png_sizeof(msg);
png_memcpy(text + prefix_size, msg, text_size);
buffer_size = text_size;
break;
}
if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
{
if (text == NULL) /* Initialize the decompression buffer */
{
text_size = expanded_size;
text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
if (text == NULL)
{
png_error(png_ptr,
"Not enough memory to decompress chunk.");
text_size = 0;
break;
}
png_memcpy(text + prefix_size, png_ptr->zbuf,
text_size - prefix_size);
png_memcpy(text, png_ptr->chunkdata, prefix_size);
*(text + text_size) = 0x00;
buffer_size = text_size;
}
}
if (ret == Z_STREAM_END)
break;
else
{
png_ptr->zstream.next_out = png_ptr->zbuf;
png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
}
}
if (ret != Z_STREAM_END)
{
#if defined(PNG_STDIO_SUPPORTED) && !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);
#else #else
png_warning(png_ptr, if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
"Incomplete compressed datastream in chunk other than IDAT"); prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
#endif #endif
text_size = prefix_size; png_warning(png_ptr, "Exceeded size limit while expanding chunk");
if (text == NULL)
/* 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.
*/
else 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); png_memcpy(text, png_ptr->chunkdata, prefix_size);
if (text == NULL) new_size = png_inflate(png_ptr,
{ (png_bytep)(png_ptr->chunkdata + prefix_size),
png_free(png_ptr, png_ptr->chunkdata); chunklength - prefix_size,
png_ptr->chunkdata = NULL; (png_bytep)(text + prefix_size), expanded_size);
png_error(png_ptr, "Not enough memory for text"); text[prefix_size + expanded_size] = 0; /* just in case */
}
png_memcpy(text, png_ptr->chunkdata, prefix_size); if (new_size == expanded_size)
} {
*(text + text_size) = 0x00; 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);
}
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, png_ptr->chunkdata);
png_ptr->chunkdata = text;
*newlength=text_size;
} }
else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
{ {
#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
char umsg[50]; char umsg[50];
png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type); #if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d", comp_type);
png_warning(png_ptr, umsg); png_warning(png_ptr, umsg);
#else #else
png_warning(png_ptr, "Unknown zTXt compression type"); png_warning(png_ptr, "Unknown zTXt compression type");
#endif #endif
*(png_ptr->chunkdata + prefix_size) = 0x00; /* The recovery is to simply drop the data. */
*newlength = prefix_size;
} }
/* 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 #endif
@ -3156,7 +3119,7 @@ png_read_finish_row(png_structp png_ptr)
{ {
if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
png_ptr->idat_size) png_ptr->idat_size)
png_warning(png_ptr, "Extra compressed data"); png_warning(png_ptr, "Extra compressed data.");
png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
break; break;
@ -3178,7 +3141,7 @@ png_read_finish_row(png_structp png_ptr)
} }
if (png_ptr->idat_size || png_ptr->zstream.avail_in) if (png_ptr->idat_size || png_ptr->zstream.avail_in)
png_warning(png_ptr, "Extra compression data"); png_warning(png_ptr, "Extra compression data.");
inflateReset(&png_ptr->zstream); inflateReset(&png_ptr->zstream);