[libpng16] Changed png_inflate() and calling routines to avoid overflow
problems. This is an intermediate check-in that solves the immediate problems
and introduces one performance improvement (avoiding a copy via png_ptr->zbuf.)
Further changes will be made to make ICC profile handling more secure.
diff --git a/ANNOUNCE b/ANNOUNCE
index b343150..80eb624 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -261,6 +261,10 @@
Version 1.6.0beta16 [March 4, 2012]
Relocated palette-index checking function from pngrutil.c to pngtrans.c
Added palette-index checking while writing.
+ Changed png_inflate() and calling routines to avoid overflow problems.
+ This is an intermediate check-in that solves the immediate problems and
+ introduces one performance improvement (avoiding a copy via png_ptr->zbuf.)
+ Further changes will be made to make ICC profile handling more secure.
Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options
declares 'index' as a global, causing a warning if it is used as a local
variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit)
diff --git a/CHANGES b/CHANGES
index d50820c..9647c2e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4012,6 +4012,10 @@
Version 1.6.0beta16 [March 4, 2012]
Relocated palette-index checking function from pngrutil.c to pngtrans.c
Added palette-index checking while writing.
+ Changed png_inflate() and calling routines to avoid overflow problems.
+ This is an intermediate check-in that solves the immediate problems and
+ introduces one performance improvement (avoiding a copy via png_ptr->zbuf.)
+ Further changes will be made to make ICC profile handling more secure.
Fixed build warnings (MSVC, GCC, GCC v3). Cygwin GCC with default options
declares 'index' as a global, causing a warning if it is used as a local
variable. GCC 64-bit warns about assigning a (size_t) (unsigned 64-bit)
diff --git a/png.h b/png.h
index 8affd44..fc52922 100644
--- a/png.h
+++ b/png.h
@@ -1,7 +1,7 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.0beta16 - March 3, 2012
+ * libpng version 1.6.0beta16 - March 4, 2012
* Copyright (c) 1998-2012 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.)
@@ -11,7 +11,7 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.6.0beta16 - March 3, 2012: Glenn
+ * libpng versions 0.97, January 1998, through 1.6.0beta16 - March 4, 2012: Glenn
* See also "Contributing Authors", below.
*
* Note about libpng version numbers:
@@ -198,7 +198,7 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.2.6, August 15, 2004, through 1.6.0beta16, March 3, 2012, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.6.0beta16, March 4, 2012, are
* Copyright (c) 2004, 2006-2012 Glenn Randers-Pehrson, and are
* distributed according to the same disclaimer and license as libpng-1.2.5
* with the following individual added to the list of Contributing Authors:
@@ -310,7 +310,7 @@
* Y2K compliance in libpng:
* =========================
*
- * March 3, 2012
+ * March 4, 2012
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
@@ -376,7 +376,7 @@
/* Version information for png.h - this should match the version in png.c */
#define PNG_LIBPNG_VER_STRING "1.6.0beta16"
#define PNG_HEADER_VERSION_STRING \
- " libpng version 1.6.0beta16 - March 3, 2012\n"
+ " libpng version 1.6.0beta16 - March 4, 2012\n"
#define PNG_LIBPNG_VER_SONUM 16
#define PNG_LIBPNG_VER_DLLNUM 16
diff --git a/pngpriv.h b/pngpriv.h
index eed4e25..f9451f0 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -822,14 +822,7 @@
/* Read bytes into buf, and update png_ptr->crc */
PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf,
- png_size_t length),PNG_EMPTY);
-
-/* Decompress data in a chunk that uses compression */
-#if defined(PNG_READ_COMPRESSED_TEXT_SUPPORTED)
-PNG_INTERNAL_FUNCTION(void,png_decompress_chunk,(png_structrp png_ptr,
- int comp_type, png_size_t chunklength, png_size_t prefix_length,
- png_size_t *data_length),PNG_EMPTY);
-#endif
+ png_uint_32 length),PNG_EMPTY);
/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,
diff --git a/pngread.c b/pngread.c
index aad2f82..fb9566c 100644
--- a/pngread.c
+++ b/pngread.c
@@ -491,8 +491,7 @@
png_ptr->zstream.next_in = png_ptr->zbuf;
if (png_ptr->zbuf_size > png_ptr->idat_size)
png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
- png_crc_read(png_ptr, png_ptr->zbuf,
- (png_size_t)png_ptr->zstream.avail_in);
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
png_ptr->idat_size -= png_ptr->zstream.avail_in;
}
diff --git a/pngrutil.c b/pngrutil.c
index 9c1d996..ae3d148 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -186,7 +186,7 @@
/* Read data, and (optionally) run it through the CRC. */
void /* PRIVATE */
-png_crc_read(png_structrp png_ptr, png_bytep buf, png_size_t length)
+png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
{
if (png_ptr == NULL)
return;
@@ -203,10 +203,10 @@
int /* PRIVATE */
png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
{
- png_size_t i;
- png_size_t istop = png_ptr->zbuf_size;
+ png_uint_32 i;
+ uInt istop = png_ptr->zbuf_size;
- for (i = (png_size_t)skip; i > istop; i -= istop)
+ for (i = skip; i > istop; i -= istop)
{
png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
}
@@ -278,11 +278,44 @@
}
#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
-static png_size_t
-png_inflate(png_structrp png_ptr, png_bytep data, png_size_t size,
- png_bytep output, png_size_t output_size)
+/* png_inflate: returns one of the following error codes. If output is not NULL
+ * the uncompressed data is placed there, up to output_size. output_size is
+ * adjusted to the actual amount of uncompressed data. If
+ * PNG_INFLATE_TRUNCATED is returned partial output will have been produced; no
+ * error or warning is produced in this case.
+ */
+#define PNG_INFLATE_OK 1
+#define PNG_INFLATE_TRUNCATED 2 /* output_size will be unchanged */
+#define PNG_INFLATE_ERROR 3 /* a chunk warning has been output */
+
+static void
+stash_error(png_structrp png_ptr, png_const_charp message)
{
- png_size_t count = 0;
+ size_t len = strlen(message);
+
+ if (len >= png_ptr->zbuf_size)
+ len = png_ptr->zbuf_size-1;
+
+ memcpy(png_ptr->zbuf, message, len);
+ png_ptr->zbuf[len] = 0;
+}
+
+static int
+png_inflate(png_structrp png_ptr, png_bytep data, png_uint_32 input_size,
+ png_bytep output, png_alloc_size_t *output_size)
+{
+ int ret;
+ png_alloc_size_t avail_out = *output_size;
+ png_uint_32 avail_in = input_size;
+
+ /* TODO: PROBLEM: png_ptr-zstream is not reset via inflateReset after reading
+ * the image, consequently the first compressed chunk (zTXt or iTXt) after
+ * the data gets a 'finished' stream and the first call to inflate returns
+ * zero decompressed bytes. This was handled silently before 1.6 by
+ * returning empty uncompressed data. This is a temporary work-round (it's
+ * harmless if the stream is already reset).
+ */
+ inflateReset(&png_ptr->zstream);
/* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
* even necessarily handle 65536 bytes) because the type uInt is "16 bits or
@@ -294,13 +327,21 @@
* at least some of the use by some period of time.
*/
png_ptr->zstream.next_in = data;
- /* avail_in is set below from 'size' */
+ /* avail_in and avail_out are set below from 'size' */
png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.avail_out = 0;
- while (1)
+ /* Read directly into the output if it is available (this is set to
+ * png_ptr->zbuf below if output is NULL).
+ */
+ if (output != NULL)
+ png_ptr->zstream.next_out = output;
+
+ do
{
- int ret, avail;
+ uInt avail;
+ /* zlib INPUT BUFFER */
/* The setting of 'avail_in' used to be outside the loop; by setting it
* inside it is possible to chunk the input to zlib and simply rely on
* zlib to advance the 'next_in' pointer. This allows arbitrary amounts o
@@ -308,96 +349,111 @@
* window save (png_memcpy of up to 32768 output bytes) every ZLIB_IO_MAX
* input bytes.
*/
- if (png_ptr->zstream.avail_in == 0 && size > 0)
+ avail_in += png_ptr->zstream.avail_in; /* not consumed last time */
+
+ avail = ZLIB_IO_MAX;
+
+ if (avail_in < avail)
+ avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */
+
+ avail_in -= avail;
+ png_ptr->zstream.avail_in = avail;
+
+ /* zlib OUTPUT BUFFER */
+ avail_out += png_ptr->zstream.avail_out; /* not written last time */
+
+ avail = ZLIB_IO_MAX; /* maximum zlib can process */
+
+ if (output == NULL)
{
- if (size <= ZLIB_IO_MAX)
+ /* Reset the output buffer each time round if output is NULL and make
+ * available the full buffer, up to 'remaining_space'
+ */
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ if (png_ptr->zbuf_size < avail)
+ avail = png_ptr->zbuf_size;
+ }
+
+ if (avail_out < avail)
+ avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */
+
+ png_ptr->zstream.avail_out = avail;
+ avail_out -= avail;
+
+ /* zlib inflate call */
+ /* In fact 'avail_out' may be 0 at this point, that happens at the end of
+ * the read when the final LZ end code was not passed at the end of the
+ * previous chunk of input data. Tell zlib if we have reached the end of
+ * the output buffer.
+ *
+ * TODO: this prevents multiple calls to inflate, but may help inflate
+ * avoid overhead. Make using Z_FINISH an option for the caller.
+ */
+ ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : Z_FINISH);
+ } while (ret == Z_OK);
+
+ /* Claw back the 'size' and 'remaining_space' byte counts. */
+ avail_in += png_ptr->zstream.avail_in;
+ avail_out += png_ptr->zstream.avail_out;
+
+ /* Always reset the zstream, it must be left in inflateInit state.
+ *
+ * TODO: don't do this on Z_BUF_ERROR and no remaining space, then the
+ * caller can use png_inflate incrementally. Also change to using the
+ * same approach as in the write code - init and reset only on demand.
+ */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->zstream.avail_out = 0;
+ inflateReset(&png_ptr->zstream);
+
+ /* Update the output size if the output was not filled.
+ *
+ * TODO: do this with 'size' as well, not currently a parameter.
+ */
+ if (avail_out > 0)
+ *output_size -= avail_out;
+
+ /* Error messages are stashed in png_ptr->zbuf, to avoid any errors in the
+ * errors do this first:
+ */
+ png_ptr->zbuf[0] = 0;
+
+ switch (ret)
+ {
+ case Z_STREAM_END:
+ return PNG_INFLATE_OK;
+
+ case Z_BUF_ERROR: /* no progress in zlib */
+ if (avail_out > 0) /* input truncated */
{
- /* The value is less than ZLIB_IO_MAX so the cast is safe: */
- png_ptr->zstream.avail_in = (uInt)size;
- size = 0;
+ stash_error(png_ptr, "LZ data truncated");
+ return PNG_INFLATE_ERROR;
}
+ else if (avail_in > 0) /* output truncated */
+ {
+ /* TODO: currently restarting a partial read isn't supporte because
+ * of the inflateReset above, change this to do the Reset/Init on
+ * demand.
+ */
+ stash_error(png_ptr, "uncompressed data too large");
+ return PNG_INFLATE_TRUNCATED;
+ }
+
+ default:
+ /* Everything else is an error, expect 'Z_DATA_ERROR' and
+ * zstream.msg to be non-NULL. In any case just copy something
+ * into zbuf and return the error code.
+ */
+ if (png_ptr->zstream.msg != NULL)
+ stash_error(png_ptr, png_ptr->zstream.msg);
+
else
- {
- png_ptr->zstream.avail_in = ZLIB_IO_MAX;
- size -= ZLIB_IO_MAX;
- }
- }
+ stash_error(png_ptr, "LZ data damaged");
- /* 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 = png_ptr->zbuf_size;
-
- ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
- avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
-
- /* 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)
- {
- png_size_t space = avail; /* > 0, see above */
-
- if (output != 0 && output_size > count)
- {
- png_size_t copy = output_size - count;
-
- if (space < copy)
- copy = space;
-
- png_memcpy(output + count, png_ptr->zbuf, copy);
- }
- count += space;
- }
-
- if (ret == Z_OK)
- continue;
-
- /* Termination conditions - always reset the zstream, it
- * must be left in inflateInit state.
- */
- 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.
- */
-# ifdef PNG_WARNINGS_SUPPORTED
- {
- png_const_charp msg;
-
- if (png_ptr->zstream.msg != 0)
- msg = png_ptr->zstream.msg;
-
- else switch (ret)
- {
- case Z_BUF_ERROR:
- msg = "Buffer error in compressed datastream";
- break;
-
- case Z_DATA_ERROR:
- msg = "Data error in compressed datastream";
- break;
-
- default:
- msg = "Incomplete compressed datastream";
- break;
- }
-
- png_chunk_warning(png_ptr, msg);
- }
-# endif
-
- /* 0 means an error - notice that this code simply ignores
- * zero length compressed chunks as a result.
- */
- return 0;
+ return PNG_INFLATE_ERROR;
}
}
@@ -408,115 +464,104 @@
* 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_structrp png_ptr, int comp_type,
- png_size_t chunklength,
- png_size_t prefix_size, png_size_t *newlength)
+static png_const_charp
+png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength,
+ png_uint_32 prefix_size,
+ png_alloc_size_t *newlength /* must be initialized to the maximum! */,
+ int terminate /*add a '\0' to the end of the uncompressed data*/)
{
- /* 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 */
- }
+ /* TODO: implement different limits for different types of chunk.
+ *
+ * The caller supplies *newlength set to the maximum length of the
+ * uncompressed data, but this routine allocates space for the prefix and
+ * maybe a '\0' terminator too. We have to assume that 'prefix_size' is
+ * limited only by the maximum chunk size.
+ */
+ png_alloc_size_t limit = PNG_SIZE_MAX;
- 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
-# ifdef PNG_USER_CHUNK_MALLOC_MAX
- if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
- prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
+# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
+ if (png_ptr->user_chunk_malloc_max > 0 &&
+ png_ptr->user_chunk_malloc_max < limit)
+ limit = png_ptr->user_chunk_malloc_max;
+# elif PNG_USER_CHUNK_MALLOC_MAX > 0
+ if (PNG_USER_CHUNK_MALLOC_MAX < limit)
+ limit = PNG_USER_CHUNK_MALLOC_MAX;
# endif
-#endif
- 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 if (expanded_size > 0)
-#else
- if (expanded_size > 0)
-#endif
+ if (limit >= prefix_size + (terminate != 0))
+ {
+ limit -= prefix_size + (terminate != 0);
+
+ if (limit < *newlength)
+ *newlength = limit;
+
+ switch (png_inflate(png_ptr,
+ (png_bytep)png_ptr->chunkdata + prefix_size,
+ chunklength - prefix_size, NULL /* output */, newlength))
{
- /* Success (maybe) - really uncompress the chunk. */
- png_size_t new_size = 0;
- png_charp text = (png_charp)png_malloc_warn(png_ptr,
- prefix_size + expanded_size + 1);
-
- if (text != NULL)
- {
- 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)
+ case PNG_INFLATE_OK:
+ /* Success (maybe) - really uncompress the chunk. */
{
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = text;
- *newlength = prefix_size + expanded_size;
- return; /* The success return! */
+ /* Because of the limit checks above we know that the new,
+ * expanded, size will fit in a size_t (let alone an
+ * png_alloc_size_t). Use png_malloc_base here to avoid an
+ * extra OOM message.
+ */
+ png_alloc_size_t new_size = *newlength;
+ png_bytep text = png_voidcast(png_bytep, png_malloc_base(
+ png_ptr, prefix_size + new_size + (terminate != 0)));
+
+ if (text == NULL)
+ break; /* out of memory */
+
+ /* This should now work, although it is possible a logic
+ * error might result.
+ */
+ switch (png_inflate(png_ptr, (png_bytep)png_ptr->chunkdata +
+ prefix_size, chunklength - prefix_size, text + prefix_size,
+ newlength))
+ {
+ case PNG_INFLATE_OK:
+ if (new_size == *newlength)
+ {
+ if (terminate)
+ text[prefix_size + *newlength] = 0;
+
+ if (prefix_size > 0)
+ png_memcpy(text, png_ptr->chunkdata, prefix_size);
+
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = (png_charp)text;
+ return NULL;
+ }
+
+ /* This is an unexpected internal error. */
+ /* FALL THROUGH */
+
+ case PNG_INFLATE_TRUNCATED:
+ png_free(png_ptr, text);
+ return "libpng inflate error";
+
+ default: /* PNG_INFLATE_ERROR */
+ png_free(png_ptr, text);
+ return (png_const_charp)png_ptr->zbuf;
+ }
}
- png_warning(png_ptr, "png_inflate logic error");
- png_free(png_ptr, text);
- }
+ case PNG_INFLATE_TRUNCATED:
+ /* This means that there wasn't enough space to uncompress the
+ * chunk.
+ */
+ break;
- else
- png_warning(png_ptr, "Not enough memory to decompress chunk");
+ default: /* PNG_INFLATE_ERROR */
+ /* png_inflate puts the error message in zbuf. */
+ return (png_const_charp)png_ptr->zbuf;
}
}
- else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
- {
- PNG_WARNING_PARAMETERS(p)
- png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type);
- png_formatted_warning(png_ptr, p, "Unknown compression type @1");
-
- /* The recovery is to simply drop the data. */
- }
-
- /* 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_charp)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;
+ /* out of memory returns. */
+ return "insufficient memory";
}
#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
@@ -850,7 +895,7 @@
void /* PRIVATE */
png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t truelen;
+ unsigned int truelen;
png_byte buf[4];
png_debug(1, "in png_handle_sBIT");
@@ -884,7 +929,7 @@
truelen = 3;
else
- truelen = (png_size_t)png_ptr->channels;
+ truelen = png_ptr->channels;
if (length != truelen || length > 4)
{
@@ -1237,13 +1282,8 @@
png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
/* Note: this does not properly handle chunks that are > 64K under DOS */
{
- png_byte compression_type;
- png_bytep pC;
- png_charp profile;
- png_uint_32 skip = 0;
- png_uint_32 profile_size;
- png_alloc_size_t profile_length;
- png_size_t slength, prefix_length, data_length;
+ png_uint_32 keyword_length;
+ png_const_charp error_message = NULL;
png_debug(1, "in png_handle_iCCP");
@@ -1252,118 +1292,126 @@
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
- png_warning(png_ptr, "Invalid iCCP after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "Invalid iCCP after IDAT");
return;
}
else if (png_ptr->mode & PNG_HAVE_PLTE)
- /* Should be an error, but we can cope with it */
- png_warning(png_ptr, "Out of place iCCP chunk");
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
{
- png_warning(png_ptr, "Duplicate iCCP chunk");
+ /* Ignore out-of-place iCCP chunks because other implementations may
+ * *have* to do so, so it is misleading if libpng handles them.
+ */
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "Out of place iCCP chunk");
return;
}
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+ if (info_ptr != NULL && (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB)))
{
- png_warning(png_ptr, "iCCP chunk too large to fit in memory");
- skip = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "Duplicate color profile");
+ return;
}
-#endif
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)png_ptr->chunkdata, slength);
+ /* TODO: read the chunk in pieces, validating it as we go. */
+ png_ptr->chunkdata = png_voidcast(png_charp, png_malloc(png_ptr, length));
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
- if (png_crc_finish(png_ptr, skip))
+ if (png_crc_finish(png_ptr, 0))
{
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
return;
}
- png_ptr->chunkdata[slength] = 0x00;
-
- for (profile = png_ptr->chunkdata; *profile; profile++)
+ /* TODO: also check that the keyword contents match the spec! */
+ for (keyword_length = 0;
+ keyword_length < length && png_ptr->chunkdata[keyword_length] != 0;
+ ++keyword_length)
/* Empty loop to find end of name */ ;
- ++profile;
+ if (keyword_length > 79 || keyword_length < 1)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_chunk_benign_error(png_ptr, "Bad iCCP keyword");
+ return;
+ }
- /* There should be at least one zero (the compression type byte)
- * following the separator, and we should be on it
+ /* There should be at least one zero (the compression type byte) following
+ * the separator followed by some LZ data; check for at least one byte.
+ * Since a chunk length is no more than 2^31 the addition below is safe.
*/
- if (profile >= png_ptr->chunkdata + slength - 1)
+ if (keyword_length + 3 >= length)
{
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
- png_warning(png_ptr, "Malformed iCCP chunk");
+ png_chunk_benign_error(png_ptr, "iCCP chunk too short");
return;
}
- /* 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
- wrote nonzero) */
- }
-
- 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, 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)(png_ptr->chunkdata + prefix_length);
- profile_size = ((*(pC )) << 24) |
- ((*(pC + 1)) << 16) |
- ((*(pC + 2)) << 8) |
- ((*(pC + 3)) );
-
- /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
- * because profile_size is a 32 bit value.
+ /* We only understand '0' compression - deflate - so if we get a different
+ * value we can't safely decode the chunk.
*/
- if (profile_size < profile_length)
- profile_length = profile_size;
-
- /* And the following guarantees that profile_size == profile_length. */
- if (profile_size > profile_length)
+ if (png_ptr->chunkdata[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)
{
- PNG_WARNING_PARAMETERS(p)
-
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
-
- png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size);
- png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length);
- png_formatted_warning(png_ptr, p,
- "Ignoring iCCP chunk with declared size = @1 and actual length = @2");
+ png_chunk_benign_error(png_ptr, "Bad compression type in iCCP chunk");
return;
}
- png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
- compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
- profile_size);
+ {
+ png_alloc_size_t uncompressed_length;
+
+ /* TODO: this is slightly broken, an ICC profile can be up to 2^32-1 bytes
+ * in length, but it is stored here with the keyword and the compression
+ * type prefixed to it. This means that on 32-bit systems the code can't
+ * accept, or express, the maximum length.
+ */
+ if (PNG_SIZE_MAX > 0xffffffffU/*ICC profile maximum*/)
+ uncompressed_length = 0xffffffffU;
+
+ else
+ uncompressed_length = PNG_SIZE_MAX;
+
+ /* TODO: at present png_decompress_chunk imposes a single application
+ * level memory limit, this should be split to different values for iCCP
+ * and text chunks.
+ */
+ error_message = png_decompress_chunk(png_ptr, length, keyword_length+2,
+ &uncompressed_length, 0/*do not terminate*/);
+
+ if (error_message == NULL)
+ {
+ /* It worked; png_ptr->chunkdata now contains the full uncompressed ICC
+ * profile. The cast below is safe because of the checks above, the
+ * final uncompressed length can be at most 2^32-1
+ */
+ png_uint_32 profile_length = (png_uint_32)uncompressed_length;
+ png_bytep profile = (png_bytep)png_ptr->chunkdata + (keyword_length+2);
+
+ /* Now perform some basic checks.
+ *
+ * TODO: do a lot more checks, the format is pretty simple, at least
+ * check that the whole tag table is there.
+ */
+ if (profile_length > 132 && png_get_uint_32(profile) == profile_length)
+ png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
+ PNG_COMPRESSION_TYPE_BASE, profile, profile_length);
+
+ else
+ error_message = "Malformed ICC profile";
+ }
+ }
+
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
+
+ if (error_message != NULL)
+ png_chunk_benign_error(png_ptr, error_message);
}
#endif /* PNG_READ_iCCP_SUPPORTED */
@@ -1429,8 +1477,7 @@
* that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
* potential breakage point if the types in pngconf.h aren't exactly right.
*/
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
if (png_crc_finish(png_ptr, skip))
{
@@ -1439,6 +1486,7 @@
return;
}
+ slength = length;
png_ptr->chunkdata[slength] = 0x00;
for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
@@ -1606,7 +1654,7 @@
return;
}
- png_crc_read(png_ptr, buf, (png_size_t)length);
+ png_crc_read(png_ptr, buf, length);
png_ptr->num_trans = 1;
png_ptr->trans_color.red = png_get_uint_16(buf);
png_ptr->trans_color.green = png_get_uint_16(buf + 2);
@@ -1636,7 +1684,7 @@
return;
}
- png_crc_read(png_ptr, readbuf, (png_size_t)length);
+ png_crc_read(png_ptr, readbuf, length);
png_ptr->num_trans = (png_uint_16)length;
}
@@ -1662,7 +1710,7 @@
void /* PRIVATE */
png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t truelen;
+ unsigned int truelen;
png_byte buf[6];
png_color_16 background;
@@ -1923,7 +1971,6 @@
png_byte type, nparams;
png_charp buf, units, endptr;
png_charpp params;
- png_size_t slength;
int i;
png_debug(1, "in png_handle_pCAL");
@@ -1956,8 +2003,7 @@
return;
}
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
if (png_crc_finish(png_ptr, 0))
{
@@ -1966,13 +2012,13 @@
return;
}
- png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
+ png_ptr->chunkdata[length] = 0x00; /* Null terminate the last string */
png_debug(3, "Finding end of pCAL purpose string");
for (buf = png_ptr->chunkdata; *buf; buf++)
/* Empty loop */ ;
- endptr = png_ptr->chunkdata + slength;
+ endptr = png_ptr->chunkdata + length;
/* We need to have at least 12 bytes after the purpose string
* in order to get the parameter information.
@@ -2105,8 +2151,8 @@
return;
}
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
+ slength = length;
png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
if (png_crc_finish(png_ptr, 0))
@@ -2217,7 +2263,6 @@
png_charp key;
png_charp text;
png_uint_32 skip = 0;
- png_size_t slength;
int ret;
png_debug(1, "in png_handle_tEXt");
@@ -2265,8 +2310,7 @@
return;
}
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
if (png_crc_finish(png_ptr, skip))
{
@@ -2277,12 +2321,12 @@
key = png_ptr->chunkdata;
- key[slength] = 0x00;
+ key[length] = 0x00;
for (text = key; *text; text++)
/* Empty loop to find end of key */ ;
- if (text != key + slength)
+ if (text != key + length)
text++;
text_ptr = (png_textp)png_malloc_warn(png_ptr,
@@ -2320,11 +2364,8 @@
void /* PRIVATE */
png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
- png_charp text;
- int comp_type;
- int ret;
- png_size_t slength, prefix_len, data_len;
+ png_const_charp errmsg = NULL;
+ png_uint_32 keyword_length;
png_debug(1, "in png_handle_zTXt");
@@ -2352,29 +2393,17 @@
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
-#ifdef PNG_MAX_MALLOC_64K
- /* We will no doubt have problems with chunks even half this size, but
- * 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_crc_finish(png_ptr, length);
- return;
- }
-#endif
-
png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ png_ptr->chunkdata = png_voidcast(png_charp, png_malloc_warn(png_ptr,
+ length));
if (png_ptr->chunkdata == NULL)
{
- png_warning(png_ptr, "Out of memory processing zTXt chunk");
+ png_chunk_benign_error(png_ptr, "insufficient memory");
return;
}
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
if (png_crc_finish(png_ptr, 0))
{
@@ -2383,65 +2412,64 @@
return;
}
- png_ptr->chunkdata[slength] = 0x00;
+ /* TODO: also check that the keyword contents match the spec! */
+ for (keyword_length = 0;
+ keyword_length < length && png_ptr->chunkdata[keyword_length] != 0;
+ ++keyword_length)
+ /* Empty loop to find end of name */ ;
- for (text = png_ptr->chunkdata; *text; text++)
- /* Empty loop */ ;
+ if (keyword_length > 79 || keyword_length < 1)
+ errmsg = "bad keyword";
- /* zTXt must have some text after the chunkdataword */
- if (text >= png_ptr->chunkdata + slength - 2)
- {
- png_warning(png_ptr, "Truncated zTXt chunk");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
- }
+ /* zTXt must have some LZ data after the keyword, although it may expand to
+ * zero bytes; we need a '\0' at the end of the keyword, the compression type
+ * then the LZ data:
+ */
+ else if (keyword_length + 3 > length)
+ errmsg = "truncated";
+
+ else if (png_ptr->chunkdata[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)
+ errmsg = "unknown compression type";
else
{
- comp_type = *(++text);
+ png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;
- if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
- {
- png_warning(png_ptr, "Unknown compression type in zTXt chunk");
- comp_type = PNG_TEXT_COMPRESSION_zTXt;
- }
+ /* TODO: at present png_decompress_chunk imposes a single application
+ * level memory limit, this should be split to different values for iCCP
+ * and text chunks.
+ */
+ errmsg = png_decompress_chunk(png_ptr, length, keyword_length+2,
+ &uncompressed_length, 1/*terminate*/);
- text++; /* Skip the compression_method byte */
+ if (errmsg == NULL)
+ {
+ png_text text;
+
+ /* It worked; png_ptr->chunkdata now looks like a tEXt chunk except for
+ * the extra compression type byte and the fact that it isn't
+ * necessarily '\0' terminated.
+ */
+ png_ptr->chunkdata[uncompressed_length+(keyword_length+2)] = 0;
+
+ text.compression = PNG_TEXT_COMPRESSION_zTXt;
+ text.key = png_ptr->chunkdata;
+ text.text = png_ptr->chunkdata + keyword_length+2;
+ text.text_length = uncompressed_length;
+ text.itxt_length = 0;
+ text.lang = NULL;
+ text.lang_key = NULL;
+
+ if (png_set_text_2(png_ptr, info_ptr, &text, 1))
+ errmsg = "insufficient memory to store zTXt chunk";
+ }
}
- prefix_len = text - png_ptr->chunkdata;
-
- 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_sizeof(png_text));
-
- if (text_ptr == NULL)
- {
- 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 = png_ptr->chunkdata;
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->itxt_length = 0;
- 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);
-
- png_free(png_ptr, text_ptr);
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
- if (ret)
- png_error(png_ptr, "Insufficient memory to store zTXt chunk");
+ if (errmsg != NULL)
+ png_chunk_benign_error(png_ptr, errmsg);
}
#endif
@@ -2450,12 +2478,8 @@
void /* PRIVATE */
png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
- 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_const_charp errmsg = NULL;
+ png_uint_32 prefix_length;
png_debug(1, "in png_handle_iTXt");
@@ -2483,29 +2507,17 @@
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
-#ifdef PNG_MAX_MALLOC_64K
- /* We will no doubt have problems with chunks even half this size, but
- * 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_crc_finish(png_ptr, length);
- return;
- }
-#endif
-
png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ png_ptr->chunkdata = png_voidcast(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_chunk_benign_error(png_ptr, "insufficient memory");
return;
}
- slength = (png_size_t)length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, length);
if (png_crc_finish(png_ptr, 0))
{
@@ -2514,104 +2526,103 @@
return;
}
- png_ptr->chunkdata[slength] = 0x00;
-
- for (lang = png_ptr->chunkdata; *lang; lang++)
+ /* First the keyword. */
+ for (prefix_length=0;
+ prefix_length < length && png_ptr->chunkdata[prefix_length] != 0;
+ ++prefix_length)
/* Empty loop */ ;
- lang++; /* Skip NUL separator */
+ /* Perform a basic check on the keyword length here. */
+ if (prefix_length > 79 || prefix_length < 1)
+ errmsg = "bad keyword";
- /* iTXt must have a language tag (possibly empty), two compression bytes,
- * translated keyword (possibly empty), and possibly some text after the
- * keyword
+ /* Expect keyword, compression flag, compression type, language, translated
+ * keyword (both may be empty but are 0 terminated) then the text, which may
+ * be empty.
*/
+ else if (prefix_length + 5 > length)
+ errmsg = "truncated";
- if (lang >= png_ptr->chunkdata + slength - 3)
+ else if (png_ptr->chunkdata[prefix_length+1] == 0 ||
+ (png_ptr->chunkdata[prefix_length+1] == 1 &&
+ png_ptr->chunkdata[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE))
{
- png_warning(png_ptr, "Truncated iTXt chunk");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
+ int compressed = png_ptr->chunkdata[prefix_length+1] != 0;
+ png_uint_32 language_offset, translated_keyword_offset;
+ png_alloc_size_t uncompressed_length = 0;
+
+ /* Now the language tag */
+ prefix_length += 3;
+ language_offset = prefix_length;
+
+ for (; prefix_length < length && png_ptr->chunkdata[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
+
+ /* WARNING: the length may be invalid here, this is checked below. */
+ translated_keyword_offset = ++prefix_length;
+
+ for (; prefix_length < length && png_ptr->chunkdata[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
+
+ /* prefix_length should now be at the trailing '\0' of the translated
+ * keyword, but it may already be over the end. None of this arithmetic
+ * can overflow because chunks are at most 2^31 bytes long, but on 16-bit
+ * systems the available allocaton may overflow.
+ */
+ ++prefix_length;
+
+ if (!compressed && prefix_length <= length)
+ uncompressed_length = length - prefix_length;
+
+ else if (compressed && prefix_length < length)
+ {
+ uncompressed_length = PNG_SIZE_MAX;
+
+ /* TODO: at present png_decompress_chunk imposes a single application
+ * level memory limit, this should be split to different values for
+ * iCCP and text chunks.
+ */
+ errmsg = png_decompress_chunk(png_ptr, length, prefix_length,
+ &uncompressed_length, 1/*terminate*/);
+ }
+
+ else
+ errmsg = "truncated";
+
+ if (errmsg == NULL)
+ {
+ png_text text;
+
+ png_ptr->chunkdata[uncompressed_length+prefix_length] = 0;
+
+ if (compressed)
+ text.compression = PNG_ITXT_COMPRESSION_NONE;
+
+ else
+ text.compression = PNG_ITXT_COMPRESSION_zTXt;
+
+ text.key = png_ptr->chunkdata;
+ text.lang = png_ptr->chunkdata + language_offset;
+ text.lang_key = png_ptr->chunkdata + translated_keyword_offset;
+ text.text = png_ptr->chunkdata + prefix_length;
+ text.text_length = 0;
+ text.itxt_length = uncompressed_length;
+
+ if (png_set_text_2(png_ptr, info_ptr, &text, 1))
+ errmsg = "insufficient memory";
+ }
}
else
- {
- comp_flag = *lang++;
- comp_type = *lang++;
- }
+ errmsg = "bad compression info";
- if (comp_type || (comp_flag && comp_flag != PNG_TEXT_COMPRESSION_zTXt))
- {
- png_warning(png_ptr, "Unknown iTXt compression type or method");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
- }
-
- for (lang_key = lang; *lang_key; lang_key++)
- /* 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 >= png_ptr->chunkdata + slength)
- {
- png_warning(png_ptr, "Malformed iTXt chunk");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
- }
-
- prefix_len = text - png_ptr->chunkdata;
-
- key=png_ptr->chunkdata;
-
- if (comp_flag)
- png_decompress_chunk(png_ptr, comp_type,
- (size_t)length, prefix_len, &data_len);
-
- else
- data_len = png_strlen(png_ptr->chunkdata + prefix_len);
-
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- png_sizeof(png_text));
-
- if (text_ptr == NULL)
- {
- 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 = 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 = png_ptr->chunkdata;
- text_ptr->text = png_ptr->chunkdata + prefix_len;
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, text_ptr);
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
- if (ret)
- png_error(png_ptr, "Insufficient memory to store iTXt chunk");
+ if (errmsg != NULL)
+ png_chunk_benign_error(png_ptr, errmsg);
}
#endif