[master] Revised png_decompress_chunk() to improve speed and memory

usage when decoding large chunks.
This commit is contained in:
Glenn Randers-Pehrson 2010-01-22 22:50:46 -06:00
parent 610e7b5bd6
commit 1a86bd2a09
3 changed files with 53 additions and 33 deletions

View File

@ -895,14 +895,15 @@ png_get_user_height_max (png_structp png_ptr)
png_uint_32 PNGAPI png_uint_32 PNGAPI
png_get_chunk_cache_max (png_structp png_ptr) png_get_chunk_cache_max (png_structp png_ptr)
{ {
return (png_ptr? (png_ptr->user_chunk_cache_max? 0x7fffffffL : return (png_ptr? (png_ptr->user_chunk_cache_max?
png_ptr->user_chunk_cache_max - 1) : 0); png_ptr->user_chunk_cache_max - 1 : 0x7fffffffL) : 0);
} }
/* This function was added to libpng 1.4.1 */ /* This function was added to libpng 1.4.1 */
png_uint_32 PNGAPI png_uint_32 PNGAPI
png_get_chunk_malloc_max (png_structp png_ptr) png_get_chunk_malloc_max (png_structp png_ptr)
{ {
return (png_ptr? png_ptr->user_chunk_cache_max : 0); return (png_ptr? (png_ptr->user_chunk_malloc_max?
png_ptr->user_chunk_malloc_max : 0x7fffffffL) : 0);
} }
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

View File

@ -70,6 +70,7 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; png_ptr->user_height_max = PNG_USER_HEIGHT_MAX;
/* Added at libpng-1.4.0 */ /* Added at libpng-1.4.0 */
png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
png_ptr->user_chunk_malloc_max = png_get_chunk_malloc_max(png_ptr);
#endif #endif
#ifdef PNG_SETJMP_SUPPORTED #ifdef PNG_SETJMP_SUPPORTED

View File

@ -210,8 +210,8 @@ png_crc_error(png_structp png_ptr)
*/ */
void /* PRIVATE */ void /* PRIVATE */
png_decompress_chunk(png_structp png_ptr, int comp_type, 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"; static PNG_CONST char msg[] = "Error decoding compressed chunk";
png_charp text; png_charp text;
@ -248,12 +248,12 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
text_size = prefix_size + png_sizeof(msg) + 1; text_size = prefix_size + png_sizeof(msg) + 1;
text = (png_charp)png_malloc_warn(png_ptr, text_size); text = (png_charp)png_malloc_warn(png_ptr, text_size);
if (text == NULL) if (text == NULL)
{ {
png_error(png_ptr, png_error(png_ptr,
"Not enough memory to decompress chunk"); "Not enough memory to decompress chunk");
text_size = 0; text_size = 0;
break; break;
} }
png_memcpy(text, png_ptr->chunkdata, prefix_size); png_memcpy(text, png_ptr->chunkdata, prefix_size);
} }
@ -261,9 +261,11 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
/* Copy what we can of the error message into the text chunk */ /* Copy what we can of the error message into the text chunk */
text_size = (png_size_t)(chunklength - text_size = (png_size_t)(chunklength -
(text - png_ptr->chunkdata) - 1); (text - png_ptr->chunkdata) - 1);
if (text_size > png_sizeof(msg)) if (text_size > png_sizeof(msg))
text_size = png_sizeof(msg); text_size = png_sizeof(msg);
png_memcpy(text + prefix_size, msg, text_size); png_memcpy(text + prefix_size, msg, text_size);
buffer_size = text_size; buffer_size = text_size;
break; break;
@ -283,9 +285,9 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
text_size = 0; text_size = 0;
break; break;
} }
png_memcpy(text, png_ptr->chunkdata, prefix_size);
png_memcpy(text + prefix_size, png_ptr->zbuf, png_memcpy(text + prefix_size, png_ptr->zbuf,
text_size - prefix_size); text_size - prefix_size);
png_memcpy(text, png_ptr->chunkdata, prefix_size);
*(text + text_size) = 0x00; *(text + text_size) = 0x00;
buffer_size = text_size; buffer_size = text_size;
} }
@ -303,33 +305,49 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
buffer_size = new_text_size; buffer_size = new_text_size;
else else
buffer_size += buffer_size; buffer_size += buffer_size;
}
#ifdef PNG_CHUNK_MALLOC_LIMIT_SUPPORTED #ifdef PNG_CHUNK_MALLOC_LIMIT_SUPPORTED
if (png_ptr->user_chunk_malloc_max <= buffer_size) if (buffer_size >= png_ptr->user_chunk_malloc_max - 1)
{ {
png_free(png_ptr, tmp); if (new_text_size >=
png_warning(png_ptr, "No space for decompressed chunk"); png_ptr->user_chunk_malloc_max - 1)
text = NULL; {
} png_free(png_ptr, tmp);
png_warning(png_ptr,
"No space for decompressed chunk");
text = NULL;
}
else
{
buffer_size = png_ptr->user_chunk_malloc_max - 1;
text = (png_charp)png_malloc_warn(png_ptr,
buffer_size + 1);
}
}
else else
text = (png_charp)png_malloc_warn(png_ptr, text = (png_charp)png_malloc_warn(png_ptr,
buffer_size + 1); buffer_size + 1);
#else #else
text = (png_charp)png_malloc_warn(png_ptr, text = (png_charp)png_malloc_warn(png_ptr,
buffer_size + 1); buffer_size + 1);
#endif #endif
if (text == NULL) if (text == NULL)
{ {
png_warning(png_ptr, png_warning(png_ptr,
"Not enough memory to decompress chunk"); "Not enough memory to decompress chunk");
break; break;
} }
png_memcpy(text, tmp, text_size); png_memcpy(text, tmp, text_size);
png_free(png_ptr, tmp); png_free(png_ptr, tmp);
}
/* FIX ME: zTXt chunk written by pngtest is 6 bytes too large */
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) if (ret == Z_STREAM_END)