summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/libpng/pngrutil.c
diff options
context:
space:
mode:
authorEirik Aavitsland <eirik.aavitsland@theqtcompany.com>2015-04-08 12:30:36 +0200
committeraavit <eirik.aavitsland@theqtcompany.com>2015-04-09 12:14:28 +0000
commit68c137cc725ceadec68c455e0e3e365ecb00f2c1 (patch)
tree242485964753e2e7890015694a916c71755cdfb3 /src/3rdparty/libpng/pngrutil.c
parentf0cee4568ec3bd58cbc33108a6e606c3294e0fb3 (diff)
Update bundled libpng to version 1.6.17
Merged in the upstream version, which obsoleted many of the local patches. The remaining diff to clean 1.6.17 is archived in the qtpatches.diff file. Change-Id: I5065435dc5a922d3f4a46eb37a23a4877dde2ee6 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Diffstat (limited to 'src/3rdparty/libpng/pngrutil.c')
-rw-r--r--src/3rdparty/libpng/pngrutil.c3233
1 files changed, 1775 insertions, 1458 deletions
diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c
index aa592ccfbd..6c5c37526b 100644
--- a/src/3rdparty/libpng/pngrutil.c
+++ b/src/3rdparty/libpng/pngrutil.c
@@ -1,8 +1,8 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.5.10 [March 8, 2012]
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.17 [March 26, 2015]
+ * Copyright (c) 1998-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -18,10 +18,8 @@
#ifdef PNG_READ_SUPPORTED
-#define png_strtod(p,a,b) strtod(a,b)
-
png_uint_32 PNGAPI
-png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
+png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
@@ -40,7 +38,7 @@ png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
#define PNG_FIXED_ERROR (-1)
static png_fixed_point /* PRIVATE */
-png_get_fixed_point(png_structp png_ptr, png_const_bytep buf)
+png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
@@ -110,11 +108,11 @@ png_get_uint_16)(png_const_bytep buf)
return (png_uint_16)val;
}
-#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */
+#endif /* READ_INT_FUNCTIONS */
/* Read and check the PNG file signature */
void /* PRIVATE */
-png_read_sig(png_structp png_ptr, png_infop info_ptr)
+png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
{
png_size_t num_checked, num_to_check;
@@ -133,7 +131,7 @@ png_read_sig(png_structp png_ptr, png_infop info_ptr)
png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
png_ptr->sig_bytes = 8;
- if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
{
if (num_checked < 4 &&
png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
@@ -149,7 +147,7 @@ png_read_sig(png_structp png_ptr, png_infop info_ptr)
* 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_read_chunk_header(png_structrp png_ptr)
{
png_byte buf[8];
png_uint_32 length;
@@ -186,7 +184,7 @@ png_read_chunk_header(png_structp png_ptr)
/* 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)
+png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
{
if (png_ptr == NULL)
return;
@@ -196,40 +194,40 @@ png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t 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
+ * are reading an 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)
+png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
{
- png_size_t i;
- png_size_t istop = png_ptr->zbuf_size;
-
- for (i = (png_size_t)skip; i > istop; i -= istop)
+ /* The size of the local buffer for inflate is a good guess as to a
+ * reasonable size to use for buffering reads from the application.
+ */
+ while (skip > 0)
{
- png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
- }
+ png_uint_32 len;
+ png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
- if (i)
- {
- png_crc_read(png_ptr, png_ptr->zbuf, i);
+ len = (sizeof tmpbuf);
+ if (len > skip)
+ len = skip;
+ skip -= len;
+
+ png_crc_read(png_ptr, tmpbuf, len);
}
- if (png_crc_error(png_ptr))
+ if (png_crc_error(png_ptr) != 0)
{
- if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name) ?
- !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) :
- (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
+ if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ?
+ (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 :
+ (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0)
{
png_chunk_warning(png_ptr, "CRC error");
}
else
- {
- png_chunk_benign_error(png_ptr, "CRC error");
- return (0);
- }
+ png_chunk_error(png_ptr, "CRC error");
return (1);
}
@@ -241,13 +239,13 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip)
* the data it has read thus far.
*/
int /* PRIVATE */
-png_crc_error(png_structp png_ptr)
+png_crc_error(png_structrp png_ptr)
{
png_byte crc_bytes[4];
png_uint_32 crc;
int need_crc = 1;
- if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name))
+ if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
{
if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
@@ -256,7 +254,7 @@ png_crc_error(png_structp png_ptr)
else /* critical */
{
- if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
need_crc = 0;
}
@@ -267,7 +265,7 @@ png_crc_error(png_structp png_ptr)
/* The chunk CRC must be serialized in a single I/O call. */
png_read_data(png_ptr, crc_bytes, 4);
- if (need_crc)
+ if (need_crc != 0)
{
crc = png_get_uint_32(crc_bytes);
return ((int)(crc != png_ptr->crc));
@@ -277,248 +275,522 @@ png_crc_error(png_structp png_ptr)
return (0);
}
-#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
-static png_size_t
-png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
- png_bytep output, png_size_t output_size)
+#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\
+ defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\
+ defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\
+ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED)
+/* Manage the read buffer; this simply reallocates the buffer if it is not small
+ * enough (or if it is not allocated). The routine returns a pointer to the
+ * buffer; if an error occurs and 'warn' is set the routine returns NULL, else
+ * it will call png_error (via png_malloc) on failure. (warn == 2 means
+ * 'silent').
+ */
+static png_bytep
+png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
{
- png_size_t count = 0;
-
- /* 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
- * more". Consequently it is necessary to chunk the input to zlib. This
- * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value
- * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a
- * lower value in pngpriv.h and this may sometimes have a performance
- * advantage, because it forces access of the input data to be separated from
- * at least some of the use by some period of time.
- */
- png_ptr->zstream.next_in = data;
- /* avail_in is set below from 'size' */
- png_ptr->zstream.avail_in = 0;
+ png_bytep buffer = png_ptr->read_buffer;
- while (1)
+ if (buffer != NULL && new_size > png_ptr->read_buffer_size)
{
- int ret, avail;
+ png_ptr->read_buffer = NULL;
+ png_ptr->read_buffer = NULL;
+ png_ptr->read_buffer_size = 0;
+ png_free(png_ptr, buffer);
+ buffer = NULL;
+ }
- /* 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
- * data to be passed through zlib at the unavoidable cost of requiring a
- * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX
- * input bytes.
- */
- if (png_ptr->zstream.avail_in == 0 && size > 0)
+ if (buffer == NULL)
+ {
+ buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size));
+
+ if (buffer != NULL)
{
- if (size <= ZLIB_IO_MAX)
- {
- /* The value is less than ZLIB_IO_MAX so the cast is safe: */
- png_ptr->zstream.avail_in = (uInt)size;
- size = 0;
- }
+ png_ptr->read_buffer = buffer;
+ png_ptr->read_buffer_size = new_size;
+ }
+
+ else if (warn < 2) /* else silent */
+ {
+ if (warn != 0)
+ png_chunk_warning(png_ptr, "insufficient memory to read chunk");
else
- {
- png_ptr->zstream.avail_in = ZLIB_IO_MAX;
- size -= ZLIB_IO_MAX;
- }
+ png_chunk_error(png_ptr, "insufficient memory to read chunk");
}
+ }
- /* Reset the output buffer each time round - we empty it
- * after every inflate call.
+ return buffer;
+}
+#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */
+
+/* png_inflate_claim: claim the zstream for some nefarious purpose that involves
+ * decompression. Returns Z_OK on success, else a zlib error code. It checks
+ * the owner but, in final release builds, just issues a warning if some other
+ * chunk apparently owns the stream. Prior to release it does a png_error.
+ */
+static int
+png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
+{
+ if (png_ptr->zowner != 0)
+ {
+ char msg[64];
+
+ PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner);
+ /* So the message that results is "<chunk> using zstream"; this is an
+ * internal error, but is very useful for debugging. i18n requirements
+ * are minimal.
*/
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = png_ptr->zbuf_size;
+ (void)png_safecat(msg, (sizeof msg), 4, " using zstream");
+#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
+ png_chunk_warning(png_ptr, msg);
+ png_ptr->zowner = 0;
+#else
+ png_chunk_error(png_ptr, msg);
+#endif
+ }
- ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
- avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ /* Implementation note: unlike 'png_deflate_claim' this internal function
+ * does not take the size of the data as an argument. Some efficiency could
+ * be gained by using this when it is known *if* the zlib stream itself does
+ * not record the number; however, this is an illusion: the original writer
+ * of the PNG may have selected a lower window size, and we really must
+ * follow that because, for systems with with limited capabilities, we
+ * would otherwise reject the application's attempts to use a smaller window
+ * size (zlib doesn't have an interface to say "this or lower"!).
+ *
+ * inflateReset2 was added to zlib 1.2.4; before this the window could not be
+ * reset, therefore it is necessary to always allocate the maximum window
+ * size with earlier zlibs just in case later compressed chunks need it.
+ */
+ {
+ int ret; /* zlib return code */
+#if PNG_ZLIB_VERNUM >= 0x1240
- /* First copy/count any new output - but only if we didn't
- * get an error code.
+# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW)
+ int window_bits;
+
+ if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==
+ PNG_OPTION_ON)
+ window_bits = 15;
+
+ else
+ window_bits = 0;
+# else
+# define window_bits 0
+# endif
+#endif
+
+ /* Set this for safety, just in case the previous owner left pointers to
+ * memory allocations.
*/
- if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
- {
- png_size_t space = avail; /* > 0, see above */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->zstream.next_out = NULL;
+ png_ptr->zstream.avail_out = 0;
- if (output != 0 && output_size > count)
- {
- png_size_t copy = output_size - count;
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
+ {
+#if PNG_ZLIB_VERNUM < 0x1240
+ ret = inflateReset(&png_ptr->zstream);
+#else
+ ret = inflateReset2(&png_ptr->zstream, window_bits);
+#endif
+ }
- if (space < copy)
- copy = space;
+ else
+ {
+#if PNG_ZLIB_VERNUM < 0x1240
+ ret = inflateInit(&png_ptr->zstream);
+#else
+ ret = inflateInit2(&png_ptr->zstream, window_bits);
+#endif
- png_memcpy(output + count, png_ptr->zbuf, copy);
- }
- count += space;
+ if (ret == Z_OK)
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
if (ret == Z_OK)
- continue;
+ png_ptr->zowner = owner;
+
+ else
+ png_zstream_error(png_ptr, ret);
+
+ return ret;
+ }
+
+#ifdef window_bits
+# undef window_bits
+#endif
+}
- /* Termination conditions - always reset the zstream, it
- * must be left in inflateInit state.
+#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
+/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to
+ * allow the caller to do multiple calls if required. If the 'finish' flag is
+ * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must
+ * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and
+ * Z_OK or Z_STREAM_END will be returned on success.
+ *
+ * The input and output sizes are updated to the actual amounts of data consumed
+ * or written, not the amount available (as in a z_stream). The data pointers
+ * are not changed, so the next input is (data+input_size) and the next
+ * available output is (output+output_size).
+ */
+static int
+png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish,
+ /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr,
+ /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr)
+{
+ if (png_ptr->zowner == owner) /* Else not claimed */
+ {
+ int ret;
+ png_alloc_size_t avail_out = *output_size_ptr;
+ png_uint_32 avail_in = *input_size_ptr;
+
+ /* 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 more". Consequently it is necessary to chunk the input to
+ * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the
+ * maximum value that can be stored in a uInt.) It is possible to set
+ * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have
+ * a performance advantage, because it reduces the amount of data accessed
+ * at each step and that may give the OS more time to page it in.
*/
+ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input);
+ /* avail_in and avail_out are set below from 'size' */
png_ptr->zstream.avail_in = 0;
- inflateReset(&png_ptr->zstream);
-
- if (ret == Z_STREAM_END)
- return count; /* NOTE: may be zero. */
+ png_ptr->zstream.avail_out = 0;
- /* Now handle the error codes - the API always returns 0
- * and the error message is dumped into the uncompressed
- * buffer if available.
+ /* Read directly into the output if it is available (this is set to
+ * a local buffer below if output is NULL).
*/
-# ifdef PNG_WARNINGS_SUPPORTED
+ if (output != NULL)
+ png_ptr->zstream.next_out = output;
+
+ do
{
- png_const_charp msg;
+ uInt avail;
+ Byte local_buffer[PNG_INFLATE_BUF_SIZE];
+
+ /* 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 of data to be passed through zlib at the unavoidable cost of
+ * requiring a window save (memcpy of up to 32768 output bytes)
+ * every ZLIB_IO_MAX input bytes.
+ */
+ avail_in += png_ptr->zstream.avail_in; /* not consumed last time */
- if (png_ptr->zstream.msg != 0)
- msg = png_ptr->zstream.msg;
+ avail = ZLIB_IO_MAX;
- else switch (ret)
- {
- case Z_BUF_ERROR:
- msg = "Buffer error in compressed datastream";
- break;
+ if (avail_in < avail)
+ avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */
- case Z_DATA_ERROR:
- msg = "Data error in compressed datastream";
- break;
+ avail_in -= avail;
+ png_ptr->zstream.avail_in = avail;
- default:
- msg = "Incomplete compressed datastream";
- break;
+ /* 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)
+ {
+ /* 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 = local_buffer;
+ if ((sizeof local_buffer) < avail)
+ avail = (sizeof local_buffer);
}
- png_chunk_warning(png_ptr, msg);
- }
-# endif
+ if (avail_out < avail)
+ avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */
- /* 0 means an error - notice that this code simply ignores
- * zero length compressed chunks as a result.
+ 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.
+ */
+ ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH :
+ (finish ? Z_FINISH : Z_SYNC_FLUSH));
+ } while (ret == Z_OK);
+
+ /* For safety kill the local buffer pointer now */
+ if (output == NULL)
+ png_ptr->zstream.next_out = NULL;
+
+ /* Claw back the 'size' and 'remaining_space' byte counts. */
+ avail_in += png_ptr->zstream.avail_in;
+ avail_out += png_ptr->zstream.avail_out;
+
+ /* Update the input and output sizes; the updated values are the amount
+ * consumed or written, effectively the inverse of what zlib uses.
*/
- return 0;
+ if (avail_out > 0)
+ *output_size_ptr -= avail_out;
+
+ if (avail_in > 0)
+ *input_size_ptr -= avail_in;
+
+ /* Ensure png_ptr->zstream.msg is set (even in the success case!) */
+ png_zstream_error(png_ptr, ret);
+ return ret;
+ }
+
+ else
+ {
+ /* This is a bad internal error. The recovery assigns to the zstream msg
+ * pointer, which is not owned by the caller, but this is safe; it's only
+ * used on errors!
+ */
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
+ return Z_STREAM_ERROR;
}
}
/*
- * Decompress trailing data in a chunk. The assumption is that chunkdata
+ * Decompress trailing data in a chunk. The assumption is that read_buffer
* 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)
+static int
+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)
+# 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
+
+ if (limit >= prefix_size + (terminate != 0))
{
- png_size_t expanded_size = png_inflate(png_ptr,
- (png_bytep)(png_ptr->chunkdata + prefix_size),
- chunklength - prefix_size,
- 0, /* output */
- 0); /* output size */
+ int ret;
- /* Now check the limits on this chunk - if the limit fails the
- * compressed data will be removed, the prefix will remain.
- */
- if (prefix_size >= (~(png_size_t)0) - 1 ||
- expanded_size >= (~(png_size_t)0) - 1 - prefix_size
-#ifdef PNG_USER_LIMITS_SUPPORTED
- || (png_ptr->user_chunk_malloc_max &&
- (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
-#else
- || ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
- prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
-#endif
- )
- png_warning(png_ptr, "Exceeded size limit while expanding chunk");
+ limit -= prefix_size + (terminate != 0);
- /* 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)
+ if (limit < *newlength)
+ *newlength = limit;
+
+ /* Now try to claim the stream. */
+ ret = png_inflate_claim(png_ptr, png_ptr->chunk_name);
+
+ if (ret == Z_OK)
{
- /* 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);
+ png_uint_32 lzsize = chunklength - prefix_size;
+
+ ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
+ /* input: */ png_ptr->read_buffer + prefix_size, &lzsize,
+ /* output: */ NULL, newlength);
- if (text != NULL)
+ if (ret == Z_STREAM_END)
{
- 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)
+ /* Use 'inflateReset' here, not 'inflateReset2' because this
+ * preserves the previously decided window size (otherwise it would
+ * be necessary to store the previous window size.) In practice
+ * this doesn't matter anyway, because png_inflate will call inflate
+ * with Z_FINISH in almost all cases, so the window will not be
+ * maintained.
+ */
+ if (inflateReset(&png_ptr->zstream) == Z_OK)
{
- 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_alloc_size_t buffer_size = prefix_size + new_size +
+ (terminate != 0);
+ png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr,
+ buffer_size));
+
+ if (text != NULL)
+ {
+ ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
+ png_ptr->read_buffer + prefix_size, &lzsize,
+ text + prefix_size, newlength);
+
+ if (ret == Z_STREAM_END)
+ {
+ if (new_size == *newlength)
+ {
+ if (terminate != 0)
+ text[prefix_size + *newlength] = 0;
+
+ if (prefix_size > 0)
+ memcpy(text, png_ptr->read_buffer, prefix_size);
+
+ {
+ png_bytep old_ptr = png_ptr->read_buffer;
+
+ png_ptr->read_buffer = text;
+ png_ptr->read_buffer_size = buffer_size;
+ text = old_ptr; /* freed below */
+ }
+ }
+
+ else
+ {
+ /* The size changed on the second read, there can be no
+ * guarantee that anything is correct at this point.
+ * The 'msg' pointer has been set to "unexpected end of
+ * LZ stream", which is fine, but return an error code
+ * that the caller won't accept.
+ */
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+ }
+ }
+
+ else if (ret == Z_OK)
+ ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */
+
+ /* Free the text pointer (this is the old read_buffer on
+ * success)
+ */
+ png_free(png_ptr, text);
+ text = NULL;
+
+ /* This really is very benign, but it's still an error because
+ * the extra space may otherwise be used as a Trojan Horse.
+ */
+ if (ret == Z_STREAM_END &&
+ chunklength - prefix_size != lzsize)
+ png_chunk_benign_error(png_ptr, "extra compressed data");
+ }
+
+ else
+ {
+ /* Out of memory allocating the buffer */
+ ret = Z_MEM_ERROR;
+ png_zstream_error(png_ptr, Z_MEM_ERROR);
+ }
}
- png_warning(png_ptr, "png_inflate logic error");
- png_free(png_ptr, text);
+ else
+ {
+ /* inflateReset failed, store the error message */
+ png_zstream_error(png_ptr, ret);
+
+ if (ret == Z_STREAM_END)
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+ }
}
- else
- png_warning(png_ptr, "Not enough memory to decompress chunk");
+ else if (ret == Z_OK)
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+
+ /* Release the claimed stream */
+ png_ptr->zowner = 0;
}
+
+ else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */
+ ret = PNG_UNEXPECTED_ZLIB_RETURN;
+
+ return ret;
}
- else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
+ else
{
- 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. */
+ /* Application/configuration limits exceeded */
+ png_zstream_error(png_ptr, Z_MEM_ERROR);
+ return Z_MEM_ERROR;
}
+}
+#endif /* READ_COMPRESSED_TEXT */
- /* Generic error return - leave the prefix, delete the compressed
- * data, reallocate the chunkdata to remove the potentially large
- * amount of compressed data.
- */
+#ifdef PNG_READ_iCCP_SUPPORTED
+/* Perform a partial read and decompress, producing 'avail_out' bytes and
+ * reading from the current chunk as required.
+ */
+static int
+png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size,
+ png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size,
+ int finish)
+{
+ if (png_ptr->zowner == png_ptr->chunk_name)
{
- png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + 1);
+ int ret;
+
+ /* next_in and avail_in must have been initialized by the caller. */
+ png_ptr->zstream.next_out = next_out;
+ png_ptr->zstream.avail_out = 0; /* set in the loop */
- if (text != NULL)
+ do
{
- if (prefix_size > 0)
- png_memcpy(text, png_ptr->chunkdata, prefix_size);
+ if (png_ptr->zstream.avail_in == 0)
+ {
+ if (read_size > *chunk_bytes)
+ read_size = (uInt)*chunk_bytes;
+ *chunk_bytes -= read_size;
+
+ if (read_size > 0)
+ png_crc_read(png_ptr, read_buffer, read_size);
+
+ png_ptr->zstream.next_in = read_buffer;
+ png_ptr->zstream.avail_in = read_size;
+ }
+
+ if (png_ptr->zstream.avail_out == 0)
+ {
+ uInt avail = ZLIB_IO_MAX;
+ if (avail > *out_size)
+ avail = (uInt)*out_size;
+ *out_size -= avail;
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = text;
+ png_ptr->zstream.avail_out = avail;
+ }
- /* This is an extra zero in the 'uncompressed' part. */
- *(png_ptr->chunkdata + prefix_size) = 0x00;
+ /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all
+ * the available output is produced; this allows reading of truncated
+ * streams.
+ */
+ ret = inflate(&png_ptr->zstream,
+ *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH));
}
- /* Ignore a malloc error here - it is safe. */
+ while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0));
+
+ *out_size += png_ptr->zstream.avail_out;
+ png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */
+
+ /* Ensure the error message pointer is always set: */
+ png_zstream_error(png_ptr, ret);
+ return ret;
}
- *newlength = prefix_size;
+ else
+ {
+ png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
+ return Z_STREAM_ERROR;
+ }
}
-#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
+#endif
/* Read and check the IDHR chunk */
+
void /* PRIVATE */
-png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[13];
png_uint_32 width, height;
@@ -527,12 +799,12 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_IHDR");
- if (png_ptr->mode & PNG_HAVE_IHDR)
- png_error(png_ptr, "Out of place IHDR");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) != 0)
+ png_chunk_error(png_ptr, "out of place");
/* Check the length */
if (length != 13)
- png_error(png_ptr, "Invalid IHDR chunk");
+ png_chunk_error(png_ptr, "invalid");
png_ptr->mode |= PNG_HAVE_IHDR;
@@ -581,8 +853,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
/* Set up other useful info */
- png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
- png_ptr->channels);
+ 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", png_ptr->bit_depth);
png_debug1(3, "channels = %d", png_ptr->channels);
@@ -593,7 +864,7 @@ png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* Read and check the palette */
void /* PRIVATE */
-png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_color palette[PNG_MAX_PALETTE_LENGTH];
int num, i;
@@ -603,26 +874,33 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_PLTE");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before PLTE");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ /* Moved to before the 'after IDAT' check below because otherwise duplicate
+ * PLTE chunks are potentially ignored (the spec says there shall not be more
+ * than one PLTE, the error is not treated as benign, so this check trumps
+ * the requirement that PLTE appears before IDAT.)
+ */
+ else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
+ png_chunk_error(png_ptr, "duplicate");
+
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid PLTE after IDAT");
+ /* This is benign because the non-benign error happened before, when an
+ * IDAT was encountered in a color-mapped image with no PLTE.
+ */
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (png_ptr->mode & PNG_HAVE_PLTE)
- png_error(png_ptr, "Duplicate PLTE chunk");
-
png_ptr->mode |= PNG_HAVE_PLTE;
- if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
{
- png_warning(png_ptr,
- "Ignoring PLTE chunk in grayscale PNG");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");
return;
}
@@ -636,19 +914,18 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
{
+ png_crc_finish(png_ptr, length);
+
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
- {
- png_warning(png_ptr, "Invalid palette chunk");
- png_crc_finish(png_ptr, length);
- return;
- }
+ png_chunk_benign_error(png_ptr, "invalid");
else
- {
- png_error(png_ptr, "Invalid palette chunk");
- }
+ png_chunk_error(png_ptr, "invalid");
+
+ return;
}
+ /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
num = (int)length / 3;
#ifdef PNG_POINTER_INDEXING_SUPPORTED
@@ -687,214 +964,196 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
- else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+ else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */
{
/* If we don't want to use the data from an ancillary chunk,
* we have two options: an error abort, or a warning and we
* ignore the data in this chunk (which should be OK, since
* it's considered ancillary for a RGB or RGBA image).
+ *
+ * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the
+ * chunk type to determine whether to check the ancillary or the critical
+ * flags.
*/
- if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0)
{
- if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
- {
- png_chunk_benign_error(png_ptr, "CRC error");
- }
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0)
+ return;
else
- {
- png_chunk_warning(png_ptr, "CRC error");
- return;
- }
+ png_chunk_error(png_ptr, "CRC error");
}
/* Otherwise, we (optionally) emit a warning and use the chunk. */
- else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
- {
+ else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)
png_chunk_warning(png_ptr, "CRC error");
- }
}
#endif
+ /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its
+ * own copy of the palette. This has the side effect that when png_start_row
+ * is called (this happens after any call to png_read_update_info) the
+ * info_ptr palette gets changed. This is extremely unexpected and
+ * confusing.
+ *
+ * Fix this by not sharing the palette in this way.
+ */
png_set_PLTE(png_ptr, info_ptr, palette, num);
+ /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before
+ * IDAT. Prior to 1.6.0 this was not checked; instead the code merely
+ * checked the apparent validity of a tRNS chunk inserted before PLTE on a
+ * palette PNG. 1.6.0 attempts to rigorously follow the standard and
+ * therefore does a benign error if the erroneous condition is detected *and*
+ * cancels the tRNS if the benign error returns. The alternative is to
+ * amend the standard since it would be rather hypocritical of the standards
+ * maintainers to ignore it.
+ */
#ifdef PNG_READ_tRNS_SUPPORTED
- if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ if (png_ptr->num_trans > 0 ||
+ (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))
{
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
- {
- if (png_ptr->num_trans > (png_uint_16)num)
- {
- png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
- png_ptr->num_trans = (png_uint_16)num;
- }
+ /* Cancel this because otherwise it would be used if the transforms
+ * require it. Don't cancel the 'valid' flag because this would prevent
+ * detection of duplicate chunks.
+ */
+ png_ptr->num_trans = 0;
- if (info_ptr->num_trans > (png_uint_16)num)
- {
- png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
- info_ptr->num_trans = (png_uint_16)num;
- }
- }
+ if (info_ptr != NULL)
+ info_ptr->num_trans = 0;
+
+ png_chunk_benign_error(png_ptr, "tRNS must be after");
}
#endif
+#ifdef PNG_READ_hIST_SUPPORTED
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
+ png_chunk_benign_error(png_ptr, "hIST must be after");
+#endif
+
+#ifdef PNG_READ_bKGD_SUPPORTED
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
+ png_chunk_benign_error(png_ptr, "bKGD must be after");
+#endif
}
void /* PRIVATE */
-png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_debug(1, "in png_handle_IEND");
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
- {
- png_error(png_ptr, "No image in file");
- }
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 ||
+ (png_ptr->mode & PNG_HAVE_IDAT) == 0)
+ png_chunk_error(png_ptr, "out of place");
png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
- if (length != 0)
- {
- png_warning(png_ptr, "Incorrect IEND chunk length");
- }
-
png_crc_finish(png_ptr, length);
- PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
+ if (length != 0)
+ png_chunk_benign_error(png_ptr, "invalid");
+
+ PNG_UNUSED(info_ptr)
}
#ifdef PNG_READ_gAMA_SUPPORTED
void /* PRIVATE */
-png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_fixed_point igamma;
png_byte buf[4];
png_debug(1, "in png_handle_gAMA");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before gAMA");
-
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- png_warning(png_ptr, "Invalid gAMA after IDAT");
- png_crc_finish(png_ptr, length);
- 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 gAMA chunk");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
-#ifdef PNG_READ_sRGB_SUPPORTED
- && !(info_ptr->valid & PNG_INFO_sRGB)
-#endif
- )
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Duplicate gAMA chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 4)
{
- png_warning(png_ptr, "Incorrect gAMA chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 4);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
igamma = png_get_fixed_point(NULL, buf);
- /* Check for zero gamma or an error. */
- if (igamma <= 0)
- {
- png_warning(png_ptr,
- "Ignoring gAMA chunk with out of range gamma");
-
- return;
- }
-
-# ifdef PNG_READ_sRGB_SUPPORTED
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
- {
- if (PNG_OUT_OF_RANGE(igamma, 45500, 500))
- {
- PNG_WARNING_PARAMETERS(p)
- png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma);
- png_formatted_warning(png_ptr, p,
- "Ignoring incorrect gAMA value @1 when sRGB is also present");
- return;
- }
- }
-# endif /* PNG_READ_sRGB_SUPPORTED */
-
-# ifdef PNG_READ_GAMMA_SUPPORTED
- /* Gamma correction on read is supported. */
- png_ptr->gamma = igamma;
-# endif
- /* And set the 'info' structure members. */
- png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
+ png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma);
+ png_colorspace_sync(png_ptr, info_ptr);
}
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
void /* PRIVATE */
-png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t truelen;
+ unsigned int truelen, i;
+ png_byte sample_depth;
png_byte buf[4];
png_debug(1, "in png_handle_sBIT");
- buf[0] = buf[1] = buf[2] = buf[3] = 0;
-
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sBIT");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Invalid sBIT after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
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 sBIT chunk");
- }
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0)
{
- png_warning(png_ptr, "Duplicate sBIT chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
truelen = 3;
+ sample_depth = 8;
+ }
else
- truelen = (png_size_t)png_ptr->channels;
+ {
+ truelen = png_ptr->channels;
+ sample_depth = png_ptr->bit_depth;
+ }
if (length != truelen || length > 4)
{
- png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_chunk_benign_error(png_ptr, "invalid");
png_crc_finish(png_ptr, length);
return;
}
+ buf[0] = buf[1] = buf[2] = buf[3] = sample_depth;
png_crc_read(png_ptr, buf, truelen);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ for (i=0; i<truelen; ++i)
+ if (buf[i] == 0 || buf[i] > sample_depth)
+ {
+ png_chunk_benign_error(png_ptr, "invalid");
+ return;
+ }
+
+ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
{
png_ptr->sig_bit.red = buf[0];
png_ptr->sig_bit.green = buf[1];
@@ -917,474 +1176,418 @@ png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_cHRM_SUPPORTED
void /* PRIVATE */
-png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[32];
- png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue,
- y_blue;
+ png_xy xy;
png_debug(1, "in png_handle_cHRM");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before cHRM");
-
- else if (png_ptr->mode & PNG_HAVE_IDAT)
- {
- png_warning(png_ptr, "Invalid cHRM after IDAT");
- png_crc_finish(png_ptr, length);
- 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 cHRM chunk");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
-# ifdef PNG_READ_sRGB_SUPPORTED
- && !(info_ptr->valid & PNG_INFO_sRGB)
-# endif
- )
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Duplicate cHRM chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 32)
{
- png_warning(png_ptr, "Incorrect cHRM chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 32);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- x_white = png_get_fixed_point(NULL, buf);
- y_white = png_get_fixed_point(NULL, buf + 4);
- x_red = png_get_fixed_point(NULL, buf + 8);
- y_red = png_get_fixed_point(NULL, buf + 12);
- x_green = png_get_fixed_point(NULL, buf + 16);
- y_green = png_get_fixed_point(NULL, buf + 20);
- x_blue = png_get_fixed_point(NULL, buf + 24);
- y_blue = png_get_fixed_point(NULL, buf + 28);
-
- if (x_white == PNG_FIXED_ERROR ||
- y_white == PNG_FIXED_ERROR ||
- x_red == PNG_FIXED_ERROR ||
- y_red == PNG_FIXED_ERROR ||
- x_green == PNG_FIXED_ERROR ||
- y_green == PNG_FIXED_ERROR ||
- x_blue == PNG_FIXED_ERROR ||
- y_blue == PNG_FIXED_ERROR)
- {
- png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities");
+ xy.whitex = png_get_fixed_point(NULL, buf);
+ xy.whitey = png_get_fixed_point(NULL, buf + 4);
+ xy.redx = png_get_fixed_point(NULL, buf + 8);
+ xy.redy = png_get_fixed_point(NULL, buf + 12);
+ xy.greenx = png_get_fixed_point(NULL, buf + 16);
+ xy.greeny = png_get_fixed_point(NULL, buf + 20);
+ xy.bluex = png_get_fixed_point(NULL, buf + 24);
+ xy.bluey = png_get_fixed_point(NULL, buf + 28);
+
+ if (xy.whitex == PNG_FIXED_ERROR ||
+ xy.whitey == PNG_FIXED_ERROR ||
+ xy.redx == PNG_FIXED_ERROR ||
+ xy.redy == PNG_FIXED_ERROR ||
+ xy.greenx == PNG_FIXED_ERROR ||
+ xy.greeny == PNG_FIXED_ERROR ||
+ xy.bluex == PNG_FIXED_ERROR ||
+ xy.bluey == PNG_FIXED_ERROR)
+ {
+ png_chunk_benign_error(png_ptr, "invalid values");
return;
}
-#ifdef PNG_READ_sRGB_SUPPORTED
- if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
- {
- if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) ||
- PNG_OUT_OF_RANGE(y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(x_red, 64000, 1000) ||
- PNG_OUT_OF_RANGE(y_red, 33000, 1000) ||
- PNG_OUT_OF_RANGE(x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(y_green, 60000, 1000) ||
- PNG_OUT_OF_RANGE(x_blue, 15000, 1000) ||
- PNG_OUT_OF_RANGE(y_blue, 6000, 1000))
- {
- PNG_WARNING_PARAMETERS(p)
-
- png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white);
- png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white);
- png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red);
- png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red);
- png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green);
- png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green);
- png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue);
- png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue);
-
- png_formatted_warning(png_ptr, p,
- "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) "
- "when sRGB is also present");
- }
+ /* If a colorspace error has already been output skip this chunk */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
return;
- }
-#endif /* PNG_READ_sRGB_SUPPORTED */
-#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
- /* Store the _white values as default coefficients for the rgb to gray
- * operation if it is supported. Check if the transform is already set to
- * avoid destroying the transform values.
- */
- if (!png_ptr->rgb_to_gray_coefficients_set)
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0)
{
- /* png_set_background has not been called and we haven't seen an sRGB
- * chunk yet. Find the XYZ of the three end points.
- */
- png_XYZ XYZ;
- png_xy xy;
-
- xy.redx = x_red;
- xy.redy = y_red;
- xy.greenx = x_green;
- xy.greeny = y_green;
- xy.bluex = x_blue;
- xy.bluey = y_blue;
- xy.whitex = x_white;
- xy.whitey = y_white;
-
- if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy))
- {
- /* The success case, because XYZ_from_xy normalises to a reference
- * white Y of 1.0 we just need to scale the numbers. This should
- * always work just fine. It is an internal error if this overflows.
- */
- {
- png_fixed_point r, g, b;
- if (png_muldiv(&r, XYZ.redY, 32768, PNG_FP_1) &&
- r >= 0 && r <= 32768 &&
- png_muldiv(&g, XYZ.greenY, 32768, PNG_FP_1) &&
- g >= 0 && g <= 32768 &&
- png_muldiv(&b, XYZ.blueY, 32768, PNG_FP_1) &&
- b >= 0 && b <= 32768 &&
- r+g+b <= 32769)
- {
- /* We allow 0 coefficients here. r+g+b may be 32769 if two or
- * all of the coefficients were rounded up. Handle this by
- * reducing the *largest* coefficient by 1; this matches the
- * approach used for the default coefficients in pngrtran.c
- */
- int add = 0;
-
- if (r+g+b > 32768)
- add = -1;
- else if (r+g+b < 32768)
- add = 1;
-
- if (add != 0)
- {
- if (g >= r && g >= b)
- g += add;
- else if (r >= g && r >= b)
- r += add;
- else
- b += add;
- }
-
- /* Check for an internal error. */
- if (r+g+b != 32768)
- png_error(png_ptr,
- "internal error handling cHRM coefficients");
-
- png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r;
- png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
- }
-
- /* This is a png_error at present even though it could be ignored -
- * it should never happen, but it is important that if it does, the
- * bug is fixed.
- */
- else
- png_error(png_ptr, "internal error handling cHRM->XYZ");
- }
- }
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
+ png_colorspace_sync(png_ptr, info_ptr);
+ png_chunk_benign_error(png_ptr, "duplicate");
+ return;
}
-#endif
- png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
- x_green, y_green, x_blue, y_blue);
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
+ (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy,
+ 1/*prefer cHRM values*/);
+ png_colorspace_sync(png_ptr, info_ptr);
}
#endif
#ifdef PNG_READ_sRGB_SUPPORTED
void /* PRIVATE */
-png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- int intent;
- png_byte buf[1];
+ png_byte intent;
png_debug(1, "in png_handle_sRGB");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sRGB");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Invalid sRGB after IDAT");
- png_crc_finish(png_ptr, length);
- 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 sRGB chunk");
-
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
- {
- png_warning(png_ptr, "Duplicate sRGB chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 1)
{
- png_warning(png_ptr, "Incorrect sRGB chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- png_crc_read(png_ptr, buf, 1);
+ png_crc_read(png_ptr, &intent, 1);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- intent = buf[0];
-
- /* Check for bad intent */
- if (intent >= PNG_sRGB_INTENT_LAST)
- {
- png_warning(png_ptr, "Unknown sRGB intent");
+ /* If a colorspace error has already been output skip this chunk */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
return;
- }
-#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
+ /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
+ * this.
+ */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0)
{
- if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500, 500))
- {
- PNG_WARNING_PARAMETERS(p)
-
- png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed,
- info_ptr->gamma);
-
- png_formatted_warning(png_ptr, p,
- "Ignoring incorrect gAMA value @1 when sRGB is also present");
- }
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
+ png_colorspace_sync(png_ptr, info_ptr);
+ png_chunk_benign_error(png_ptr, "too many profiles");
+ return;
}
-#endif /* PNG_READ_gAMA_SUPPORTED */
-
-#ifdef PNG_READ_cHRM_SUPPORTED
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
- if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->x_red, 64000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->y_green, 60000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) ||
- PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000))
- {
- png_warning(png_ptr,
- "Ignoring incorrect cHRM value when sRGB is also present");
- }
-#endif /* PNG_READ_cHRM_SUPPORTED */
-
- /* This is recorded for use when handling the cHRM chunk above. An sRGB
- * chunk unconditionally overwrites the coefficients for grayscale conversion
- * too.
- */
- png_ptr->is_sRGB = 1;
-
-# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
- /* Don't overwrite user supplied values: */
- if (!png_ptr->rgb_to_gray_coefficients_set)
- {
- /* These numbers come from the sRGB specification (or, since one has to
- * pay much money to get a copy, the wikipedia sRGB page) the
- * chromaticity values quoted have been inverted to get the reverse
- * transformation from RGB to XYZ and the 'Y' coefficients scaled by
- * 32768 (then rounded).
- *
- * sRGB and ITU Rec-709 both truncate the values for the D65 white
- * point to four digits and, even though it actually stores five
- * digits, the PNG spec gives the truncated value.
- *
- * This means that when the chromaticities are converted back to XYZ
- * end points we end up with (6968,23435,2366), which, as described in
- * pngrtran.c, would overflow. If the five digit precision and up is
- * used we get, instead:
- *
- * 6968*R + 23435*G + 2365*B
- *
- * (Notice that this rounds the blue coefficient down, rather than the
- * choice used in pngrtran.c which is to round the green one down.)
- */
- png_ptr->rgb_to_gray_red_coeff = 6968; /* 0.212639005871510 */
- png_ptr->rgb_to_gray_green_coeff = 23434; /* 0.715168678767756 */
- /* png_ptr->rgb_to_gray_blue_coeff = 2366; 0.072192315360734 */
-
- /* The following keeps the cHRM chunk from destroying the
- * coefficients again in the event that it follows the sRGB chunk.
- */
- png_ptr->rgb_to_gray_coefficients_set = 1;
- }
-# endif
- png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
+ (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent);
+ png_colorspace_sync(png_ptr, info_ptr);
}
-#endif /* PNG_READ_sRGB_SUPPORTED */
+#endif /* READ_sRGB */
#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_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
+/* Note: this does not properly handle profiles 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_const_charp errmsg = NULL; /* error message output, or no error */
+ int finished = 0; /* crc checked */
png_debug(1, "in png_handle_iCCP");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before iCCP");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0)
{
- png_warning(png_ptr, "Invalid iCCP after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
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 ((png_ptr->mode & PNG_HAVE_iCCP) || (info_ptr != NULL &&
- (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB))))
+ /* Consistent with all the above colorspace handling an obviously *invalid*
+ * chunk is just ignored, so does not invalidate the color space. An
+ * alternative is to set the 'invalid' flags at the start of this routine
+ * and only clear them in they were not set before and all the tests pass.
+ * The minimum 'deflate' stream is assumed to be just the 2 byte header and
+ * 4 byte checksum. The keyword must be at least one character and there is
+ * a terminator (0) byte and the compression method.
+ */
+ if (length < 9)
{
- png_warning(png_ptr, "Duplicate iCCP chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "too short");
return;
}
- png_ptr->mode |= PNG_HAVE_iCCP;
-
-#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+ /* If a colorspace error has already been output skip this chunk */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
{
- 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);
+ return;
}
-#endif
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
-
- if (png_crc_finish(png_ptr, skip))
+ /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect
+ * this.
+ */
+ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0)
{
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
- }
+ uInt read_length, keyword_length;
+ char keyword[81];
- png_ptr->chunkdata[slength] = 0x00;
+ /* Find the keyword; the keyword plus separator and compression method
+ * bytes can be at most 81 characters long.
+ */
+ read_length = 81; /* maximum */
+ if (read_length > length)
+ read_length = (uInt)length;
- for (profile = png_ptr->chunkdata; *profile; profile++)
- /* Empty loop to find end of name */ ;
+ png_crc_read(png_ptr, (png_bytep)keyword, read_length);
+ length -= read_length;
- ++profile;
+ keyword_length = 0;
+ while (keyword_length < 80 && keyword_length < read_length &&
+ keyword[keyword_length] != 0)
+ ++keyword_length;
- /* 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, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- png_warning(png_ptr, "Malformed iCCP chunk");
- return;
- }
+ /* TODO: make the keyword checking common */
+ if (keyword_length >= 1 && keyword_length <= 79)
+ {
+ /* We only understand '0' compression - deflate - so if we get a
+ * different value we can't safely decode the chunk.
+ */
+ if (keyword_length+1 < read_length &&
+ keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE)
+ {
+ read_length -= keyword_length+2;
- /* Compression_type should always be zero */
- compression_type = *profile++;
+ if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)
+ {
+ Byte profile_header[132];
+ Byte local_buffer[PNG_INFLATE_BUF_SIZE];
+ png_alloc_size_t size = (sizeof profile_header);
- 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) */
- }
+ png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2);
+ png_ptr->zstream.avail_in = read_length;
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length, profile_header, &size,
+ 0/*finish: don't, because the output is too small*/);
- prefix_length = profile - png_ptr->chunkdata;
- png_decompress_chunk(png_ptr, compression_type,
- slength, prefix_length, &data_length);
+ if (size == 0)
+ {
+ /* We have the ICC profile header; do the basic header checks.
+ */
+ const png_uint_32 profile_length =
+ png_get_uint_32(profile_header);
- profile_length = data_length - prefix_length;
+ if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
+ keyword, profile_length) != 0)
+ {
+ /* The length is apparently ok, so we can check the 132
+ * byte header.
+ */
+ if (png_icc_check_header(png_ptr, &png_ptr->colorspace,
+ keyword, profile_length, profile_header,
+ png_ptr->color_type) != 0)
+ {
+ /* Now read the tag table; a variable size buffer is
+ * needed at this point, allocate one for the whole
+ * profile. The header check has already validated
+ * that none of these stuff will overflow.
+ */
+ const png_uint_32 tag_count = png_get_uint_32(
+ profile_header+128);
+ png_bytep profile = png_read_buffer(png_ptr,
+ profile_length, 2/*silent*/);
+
+ if (profile != NULL)
+ {
+ memcpy(profile, profile_header,
+ (sizeof profile_header));
+
+ size = 12 * tag_count;
+
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length,
+ profile + (sizeof profile_header), &size, 0);
+
+ /* Still expect a buffer error because we expect
+ * there to be some tag data!
+ */
+ if (size == 0)
+ {
+ if (png_icc_check_tag_table(png_ptr,
+ &png_ptr->colorspace, keyword, profile_length,
+ profile) != 0)
+ {
+ /* The profile has been validated for basic
+ * security issues, so read the whole thing in.
+ */
+ size = profile_length - (sizeof profile_header)
+ - 12 * tag_count;
+
+ (void)png_inflate_read(png_ptr, local_buffer,
+ (sizeof local_buffer), &length,
+ profile + (sizeof profile_header) +
+ 12 * tag_count, &size, 1/*finish*/);
+
+ if (length > 0 && !(png_ptr->flags &
+ PNG_FLAG_BENIGN_ERRORS_WARN))
+ errmsg = "extra compressed data";
+
+ /* But otherwise allow extra data: */
+ else if (size == 0)
+ {
+ if (length > 0)
+ {
+ /* This can be handled completely, so
+ * keep going.
+ */
+ png_chunk_warning(png_ptr,
+ "extra compressed data");
+ }
+
+ png_crc_finish(png_ptr, length);
+ finished = 1;
+
+# ifdef PNG_sRGB_SUPPORTED
+ /* Check for a match against sRGB */
+ png_icc_set_sRGB(png_ptr,
+ &png_ptr->colorspace, profile,
+ png_ptr->zstream.adler);
+# endif
+
+ /* Steal the profile for info_ptr. */
+ if (info_ptr != NULL)
+ {
+ png_free_data(png_ptr, info_ptr,
+ PNG_FREE_ICCP, 0);
+
+ info_ptr->iccp_name = png_voidcast(char*,
+ png_malloc_base(png_ptr,
+ keyword_length+1));
+ if (info_ptr->iccp_name != NULL)
+ {
+ memcpy(info_ptr->iccp_name, keyword,
+ keyword_length+1);
+ info_ptr->iccp_proflen =
+ profile_length;
+ info_ptr->iccp_profile = profile;
+ png_ptr->read_buffer = NULL; /*steal*/
+ info_ptr->free_me |= PNG_FREE_ICCP;
+ info_ptr->valid |= PNG_INFO_iCCP;
+ }
+
+ else
+ {
+ png_ptr->colorspace.flags |=
+ PNG_COLORSPACE_INVALID;
+ errmsg = "out of memory";
+ }
+ }
+
+ /* else the profile remains in the read
+ * buffer which gets reused for subsequent
+ * chunks.
+ */
+
+ if (info_ptr != NULL)
+ png_colorspace_sync(png_ptr, info_ptr);
+
+ if (errmsg == NULL)
+ {
+ png_ptr->zowner = 0;
+ return;
+ }
+ }
+
+ else if (size > 0)
+ errmsg = "truncated";
+
+#ifndef __COVERITY__
+ else
+ errmsg = png_ptr->zstream.msg;
+#endif
+ }
- 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;
- }
+ /* else png_icc_check_tag_table output an error */
+ }
- /* 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)) );
+ else /* profile truncated */
+ errmsg = png_ptr->zstream.msg;
+ }
- /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
- * because profile_size is a 32 bit value.
- */
- if (profile_size < profile_length)
- profile_length = profile_size;
+ else
+ errmsg = "out of memory";
+ }
- /* And the following guarantees that profile_size == profile_length. */
- if (profile_size > profile_length)
- {
- PNG_WARNING_PARAMETERS(p)
+ /* else png_icc_check_header output an error */
+ }
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ /* else png_icc_check_length output an error */
+ }
- 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");
- return;
+ else /* profile truncated */
+ errmsg = png_ptr->zstream.msg;
+
+ /* Release the stream */
+ png_ptr->zowner = 0;
+ }
+
+ else /* png_inflate_claim failed */
+ errmsg = png_ptr->zstream.msg;
+ }
+
+ else
+ errmsg = "bad compression method"; /* or missing */
+ }
+
+ else
+ errmsg = "bad keyword";
}
- png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
- compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
- profile_size);
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ else
+ errmsg = "too many profiles";
+
+ /* Failure: the reason is in 'errmsg' */
+ if (finished == 0)
+ png_crc_finish(png_ptr, length);
+
+ png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
+ png_colorspace_sync(png_ptr, info_ptr);
+ if (errmsg != NULL) /* else already output */
+ png_chunk_benign_error(png_ptr, errmsg);
}
-#endif /* PNG_READ_iCCP_SUPPORTED */
+#endif /* READ_iCCP */
#ifdef PNG_READ_sPLT_SUPPORTED
void /* PRIVATE */
-png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_sPLT(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_bytep entry_start;
+ png_bytep entry_start, buffer;
png_sPLT_t new_palette;
png_sPLT_entryp pp;
png_uint_32 data_length;
int entry_size, i;
png_uint_32 skip = 0;
- png_size_t slength;
png_uint_32 dl;
png_size_t max_dl;
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)
@@ -1402,55 +1605,53 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
#endif
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sPLT");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid sPLT after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+ if (length > 65535U)
{
- png_warning(png_ptr, "sPLT 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, "too large to fit in memory");
+ return;
}
#endif
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+ if (buffer == NULL)
+ {
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
+ return;
+ }
+
/* WARNING: this may break if size_t is less than 32 bits; it is assumed
* 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 = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, buffer, length);
- if (png_crc_finish(png_ptr, skip))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ if (png_crc_finish(png_ptr, skip) != 0)
return;
- }
- png_ptr->chunkdata[slength] = 0x00;
+ buffer[length] = 0;
- for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
- entry_start++)
+ for (entry_start = buffer; *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 > (png_bytep)png_ptr->chunkdata + slength - 2)
+ if (entry_start > buffer + length - 2)
{
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
png_warning(png_ptr, "malformed sPLT chunk");
return;
}
@@ -1458,23 +1659,19 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
new_palette.depth = *entry_start++;
entry_size = (new_palette.depth == 8 ? 6 : 10);
/* This must fit in a png_uint_32 because it is derived from the original
- * chunk data length (and use 'length', not 'slength' here for clarity -
- * they are guaranteed to be the same, see the tests above.)
+ * chunk data length.
*/
- data_length = length - (png_uint_32)(entry_start -
- (png_bytep)png_ptr->chunkdata);
+ data_length = length - (png_uint_32)(entry_start - buffer);
/* Integrity-check the data length */
- if (data_length % entry_size)
+ if ((data_length % entry_size) != 0)
{
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
png_warning(png_ptr, "sPLT chunk has bad length");
return;
}
dl = (png_int_32)(data_length / entry_size);
- max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry);
+ max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));
if (dl > max_dl)
{
@@ -1485,7 +1682,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
new_palette.nentries = (png_int_32)(data_length / entry_size);
new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
- png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
+ png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry)));
if (new_palette.entries == NULL)
{
@@ -1543,38 +1740,36 @@ 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_ptr->chunkdata;
+ new_palette.name = (png_charp)buffer;
png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
png_free(png_ptr, new_palette.entries);
}
-#endif /* PNG_READ_sPLT_SUPPORTED */
+#endif /* READ_sPLT */
#ifdef PNG_READ_tRNS_SUPPORTED
void /* PRIVATE */
-png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
png_debug(1, "in png_handle_tRNS");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before tRNS");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid tRNS after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)
{
- png_warning(png_ptr, "Duplicate tRNS chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
@@ -1584,8 +1779,8 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length != 2)
{
- png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
@@ -1600,12 +1795,12 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length != 6)
{
- png_warning(png_ptr, "Incorrect tRNS chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
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);
@@ -1614,44 +1809,43 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (!(png_ptr->mode & PNG_HAVE_PLTE))
- {
- /* Should be an error, but we can cope with it. */
- png_warning(png_ptr, "Missing PLTE before tRNS");
- }
-
- if (length > (png_uint_32)png_ptr->num_palette ||
- length > PNG_MAX_PALETTE_LENGTH)
+ if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
{
- png_warning(png_ptr, "Incorrect tRNS chunk length");
+ /* TODO: is this actually an error in the ISO spec? */
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- if (length == 0)
+ if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH ||
+ length == 0)
{
- png_warning(png_ptr, "Zero length tRNS chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
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;
}
else
{
- png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid with alpha channel");
return;
}
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
{
png_ptr->num_trans = 0;
return;
}
+ /* TODO: this is a horrible side effect in the palette case because the
+ * png_struct ends up with a pointer to the tRNS buffer owned by the
+ * png_info. Fix this.
+ */
png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
&(png_ptr->trans_color));
}
@@ -1659,43 +1853,37 @@ png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_bKGD_SUPPORTED
void /* PRIVATE */
-png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+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;
png_debug(1, "in png_handle_bKGD");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before bKGD");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ (png_ptr->mode & PNG_HAVE_PLTE) == 0))
{
- png_warning(png_ptr, "Invalid bKGD after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- !(png_ptr->mode & PNG_HAVE_PLTE))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0)
{
- png_warning(png_ptr, "Missing PLTE before bKGD");
- png_crc_finish(png_ptr, length);
- return;
- }
-
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
- {
- png_warning(png_ptr, "Duplicate bKGD chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
truelen = 1;
- else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
truelen = 6;
else
@@ -1703,14 +1891,14 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (length != truelen)
{
- png_warning(png_ptr, "Incorrect bKGD chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, truelen);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
/* We convert the index value into RGB components so that we can allow
@@ -1722,11 +1910,11 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
background.index = buf[0];
- if (info_ptr && info_ptr->num_palette)
+ if (info_ptr != NULL && info_ptr->num_palette != 0)
{
if (buf[0] >= info_ptr->num_palette)
{
- png_warning(png_ptr, "Incorrect bKGD chunk index value");
+ png_chunk_benign_error(png_ptr, "invalid index");
return;
}
@@ -1741,7 +1929,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
background.gray = 0;
}
- else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
+ else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */
{
background.index = 0;
background.red =
@@ -1765,47 +1953,40 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_hIST_SUPPORTED
void /* PRIVATE */
-png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_hIST(png_structrp png_ptr, png_inforp 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");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before hIST");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 ||
+ (png_ptr->mode & PNG_HAVE_PLTE) == 0)
{
- png_warning(png_ptr, "Invalid hIST after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0)
{
- png_warning(png_ptr, "Missing PLTE before hIST");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
- {
- png_warning(png_ptr, "Duplicate hIST chunk");
- png_crc_finish(png_ptr, length);
- return;
- }
+ num = length / 2 ;
- if (length > 2*PNG_MAX_PALETTE_LENGTH ||
- length != (unsigned int) (2*png_ptr->num_palette))
+ if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH)
{
- png_warning(png_ptr, "Incorrect hIST chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
- num = length / 2 ;
-
for (i = 0; i < num; i++)
{
png_byte buf[2];
@@ -1814,7 +1995,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
readbuf[i] = png_get_uint_16(buf);
}
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
png_set_hIST(png_ptr, info_ptr, readbuf);
@@ -1823,7 +2004,7 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_pHYs_SUPPORTED
void /* PRIVATE */
-png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[9];
png_uint_32 res_x, res_y;
@@ -1831,33 +2012,33 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_pHYs");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before pHYs");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid pHYs after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_warning(png_ptr, "Duplicate pHYs chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
- png_warning(png_ptr, "Incorrect pHYs chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 9);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
res_x = png_get_uint_32(buf);
@@ -1869,7 +2050,7 @@ png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#ifdef PNG_READ_oFFs_SUPPORTED
void /* PRIVATE */
-png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[9];
png_int_32 offset_x, offset_y;
@@ -1877,33 +2058,33 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_debug(1, "in png_handle_oFFs");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before oFFs");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid oFFs after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_warning(png_ptr, "Duplicate oFFs chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
- png_warning(png_ptr, "Incorrect oFFs chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 9);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
offset_x = png_get_int_32(buf);
@@ -1916,71 +2097,64 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#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_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_int_32 X0, X1;
png_byte type, nparams;
- png_charp buf, units, endptr;
+ png_bytep buffer, buf, units, endptr;
png_charpp params;
- png_size_t slength;
int i;
png_debug(1, "in png_handle_pCAL");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before pCAL");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid pCAL after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0)
{
- png_warning(png_ptr, "Duplicate pCAL chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
length + 1);
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
- if (png_ptr->chunkdata == NULL)
+ buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
+
+ if (buffer == NULL)
{
- png_warning(png_ptr, "No memory for pCAL purpose");
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, buffer, length);
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- }
- png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
+ buffer[length] = 0; /* Null terminate the last string */
png_debug(3, "Finding end of pCAL purpose string");
- for (buf = png_ptr->chunkdata; *buf; buf++)
+ for (buf = buffer; *buf; buf++)
/* Empty loop */ ;
- endptr = png_ptr->chunkdata + slength;
+ endptr = buffer + length;
/* 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, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
@@ -2000,15 +2174,13 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
(type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
(type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
{
- png_warning(png_ptr, "Invalid pCAL parameters for equation type");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ png_chunk_benign_error(png_ptr, "invalid parameter count");
return;
}
else if (type >= PNG_EQUATION_LAST)
{
- png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ png_chunk_benign_error(png_ptr, "unrecognized equation type");
}
for (buf = units; *buf; buf++)
@@ -2016,43 +2188,37 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_debug(3, "Allocating pCAL parameters array");
- params = (png_charpp)png_malloc_warn(png_ptr,
- (png_size_t)(nparams * png_sizeof(png_charp)));
+ params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
+ nparams * (sizeof (png_charp))));
if (params == NULL)
{
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- png_warning(png_ptr, "No memory for pCAL params");
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
/* Get pointers to the start of each parameter string. */
- for (i = 0; i < (int)nparams; i++)
+ for (i = 0; i < nparams; i++)
{
buf++; /* Skip the null string terminator from previous parameter. */
png_debug1(3, "Reading pCAL parameter %d", i);
- for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
+ for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; 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, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
png_free(png_ptr, params);
+ png_chunk_benign_error(png_ptr, "invalid data");
return;
}
}
- png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
- units, params);
+ png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,
+ (png_charp)units, params);
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
png_free(png_ptr, params);
}
#endif
@@ -2060,67 +2226,61 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#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_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_size_t slength, i;
+ png_bytep buffer;
+ png_size_t i;
int state;
png_debug(1, "in png_handle_sCAL");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before sCAL");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (png_ptr->mode & PNG_HAVE_IDAT)
+ else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{
- png_warning(png_ptr, "Invalid sCAL after IDAT");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of place");
return;
}
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0)
{
- png_warning(png_ptr, "Duplicate sCAL chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
/* Need unit type, width, \0, height: minimum 4 bytes */
else if (length < 4)
{
- png_warning(png_ptr, "sCAL chunk too short");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
length + 1);
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
- if (png_ptr->chunkdata == NULL)
+ if (buffer == NULL)
{
- png_warning(png_ptr, "Out of memory while processing sCAL chunk");
+ png_chunk_benign_error(png_ptr, "out of memory");
png_crc_finish(png_ptr, length);
return;
}
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
- png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
+ png_crc_read(png_ptr, buffer, length);
+ buffer[length] = 0; /* Null terminate the last string */
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- }
/* Validate the unit. */
- if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2)
+ if (buffer[0] != 1 && buffer[0] != 2)
{
- png_warning(png_ptr, "Invalid sCAL ignored: invalid unit");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ png_chunk_benign_error(png_ptr, "invalid unit");
return;
}
@@ -2130,70 +2290,65 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
i = 1;
state = 0;
- if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
- i >= slength || png_ptr->chunkdata[i++] != 0)
- png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
+ if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 ||
+ i >= length || buffer[i++] != 0)
+ png_chunk_benign_error(png_ptr, "bad width format");
- else if (!PNG_FP_IS_POSITIVE(state))
- png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width");
+ else if (PNG_FP_IS_POSITIVE(state) == 0)
+ png_chunk_benign_error(png_ptr, "non-positive width");
else
{
png_size_t heighti = i;
state = 0;
- if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
- i != slength)
- png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
+ if (png_check_fp_number((png_const_charp)buffer, length,
+ &state, &i) == 0 || i != length)
+ png_chunk_benign_error(png_ptr, "bad height format");
- else if (!PNG_FP_IS_POSITIVE(state))
- png_warning(png_ptr,
- "Invalid sCAL chunk ignored: non-positive height");
+ else if (PNG_FP_IS_POSITIVE(state) == 0)
+ png_chunk_benign_error(png_ptr, "non-positive height");
else
/* This is the (only) success case. */
- png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
- png_ptr->chunkdata+1, png_ptr->chunkdata+heighti);
+ png_set_sCAL_s(png_ptr, info_ptr, buffer[0],
+ (png_charp)buffer+1, (png_charp)buffer+heighti);
}
-
- /* Clean up - just free the temporarily allocated buffer. */
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
}
#endif
#ifdef PNG_READ_tIME_SUPPORTED
void /* PRIVATE */
-png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[7];
png_time mod_time;
png_debug(1, "in png_handle_tIME");
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Out of place tIME chunk");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0)
{
- png_warning(png_ptr, "Duplicate tIME chunk");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "duplicate");
return;
}
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
png_ptr->mode |= PNG_AFTER_IDAT;
if (length != 7)
{
- png_warning(png_ptr, "Incorrect tIME chunk length");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 7);
- if (png_crc_finish(png_ptr, 0))
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
mod_time.second = buf[6];
@@ -2210,14 +2365,13 @@ png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#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)
+png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
- png_textp text_ptr;
+ png_text text_info;
+ png_bytep buffer;
png_charp key;
png_charp text;
png_uint_32 skip = 0;
- png_size_t slength;
- int ret;
png_debug(1, "in png_handle_tEXt");
@@ -2232,84 +2386,59 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
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);
+ png_chunk_benign_error(png_ptr, "no space in chunk cache");
return;
}
}
#endif
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before tEXt");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
png_ptr->mode |= PNG_AFTER_IDAT;
#ifdef PNG_MAX_MALLOC_64K
- if (length > (png_uint_32)65535L)
+ if (length > 65535U)
{
- png_warning(png_ptr, "tEXt 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, "too large to fit in memory");
+ return;
}
#endif
- png_free(png_ptr, png_ptr->chunkdata);
-
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
- if (png_ptr->chunkdata == NULL)
+ if (buffer == NULL)
{
- png_warning(png_ptr, "No memory to process text chunk");
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, buffer, length);
- if (png_crc_finish(png_ptr, skip))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ if (png_crc_finish(png_ptr, skip) != 0)
return;
- }
-
- key = png_ptr->chunkdata;
- key[slength] = 0x00;
+ key = (png_charp)buffer;
+ key[length] = 0;
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,
- png_sizeof(png_text));
-
- if (text_ptr == NULL)
- {
- 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;
- text_ptr->key = key;
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->itxt_length = 0;
- text_ptr->text = text;
- text_ptr->text_length = png_strlen(text);
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- png_free(png_ptr, text_ptr);
+ text_info.compression = PNG_TEXT_COMPRESSION_NONE;
+ text_info.key = key;
+ text_info.lang = NULL;
+ text_info.lang_key = NULL;
+ text_info.itxt_length = 0;
+ text_info.text = text;
+ text_info.text_length = strlen(text);
- if (ret)
+ if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0)
png_warning(png_ptr, "Insufficient memory to process text chunk");
}
#endif
@@ -2317,13 +2446,11 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
#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_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_bytep buffer;
+ png_uint_32 keyword_length;
png_debug(1, "in png_handle_zTXt");
@@ -2338,123 +2465,101 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
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);
+ png_chunk_benign_error(png_ptr, "no space in chunk cache");
return;
}
}
#endif
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before zTXt");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
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)
+ buffer = png_read_buffer(png_ptr, length, 2/*silent*/);
+
+ if (buffer == NULL)
{
- png_warning(png_ptr, "zTXt chunk too large to fit in memory");
png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
-#endif
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ png_crc_read(png_ptr, buffer, length);
- if (png_ptr->chunkdata == NULL)
- {
- png_warning(png_ptr, "Out of memory processing zTXt chunk");
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- }
-
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
- }
+ /* TODO: also check that the keyword contents match the spec! */
+ for (keyword_length = 0;
+ keyword_length < length && buffer[keyword_length] != 0;
+ ++keyword_length)
+ /* Empty loop to find end of name */ ;
- png_ptr->chunkdata[slength] = 0x00;
+ if (keyword_length > 79 || keyword_length < 1)
+ errmsg = "bad keyword";
- for (text = png_ptr->chunkdata; *text; text++)
- /* Empty loop */ ;
+ /* 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";
- /* 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;
- }
+ else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)
+ errmsg = "unknown compression type";
else
{
- comp_type = *(++text);
-
- if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
- {
- png_warning(png_ptr, "Unknown compression type in zTXt chunk");
- comp_type = PNG_TEXT_COMPRESSION_zTXt;
- }
+ png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;
- text++; /* Skip the compression_method byte */
- }
-
- prefix_len = text - png_ptr->chunkdata;
-
- png_decompress_chunk(png_ptr, comp_type,
- (png_size_t)length, prefix_len, &data_len);
+ /* 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.
+ */
+ if (png_decompress_chunk(png_ptr, length, keyword_length+2,
+ &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
+ {
+ png_text text;
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- png_sizeof(png_text));
+ /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except
+ * for the extra compression type byte and the fact that it isn't
+ * necessarily '\0' terminated.
+ */
+ buffer = png_ptr->read_buffer;
+ buffer[uncompressed_length+(keyword_length+2)] = 0;
+
+ text.compression = PNG_TEXT_COMPRESSION_zTXt;
+ text.key = (png_charp)buffer;
+ text.text = (png_charp)(buffer + 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) != 0)
+ errmsg = "insufficient memory";
+ }
- 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;
+ else
+ errmsg = png_ptr->zstream.msg;
}
- 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
#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_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_bytep buffer;
+ png_uint_32 prefix_length;
png_debug(1, "in png_handle_iTXt");
@@ -2469,279 +2574,393 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
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);
+ png_chunk_benign_error(png_ptr, "no space in chunk cache");
return;
}
}
#endif
- if (!(png_ptr->mode & PNG_HAVE_IHDR))
- png_error(png_ptr, "Missing IHDR before iTXt");
+ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
+ png_chunk_error(png_ptr, "missing IHDR");
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
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);
+ buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
- if (png_ptr->chunkdata == NULL)
+ if (buffer == NULL)
{
- png_warning(png_ptr, "No memory to process iTXt chunk");
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "out of memory");
return;
}
- slength = length;
- png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+ png_crc_read(png_ptr, buffer, length);
- if (png_crc_finish(png_ptr, 0))
- {
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ if (png_crc_finish(png_ptr, 0) != 0)
return;
- }
- png_ptr->chunkdata[slength] = 0x00;
-
- for (lang = png_ptr->chunkdata; *lang; lang++)
+ /* First the keyword. */
+ for (prefix_length=0;
+ prefix_length < length && buffer[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 (buffer[prefix_length+1] == 0 ||
+ (buffer[prefix_length+1] == 1 &&
+ buffer[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 = buffer[prefix_length+1] != 0;
+ png_uint_32 language_offset, translated_keyword_offset;
+ png_alloc_size_t uncompressed_length = 0;
- else
- {
- comp_flag = *lang++;
- comp_type = *lang++;
- }
+ /* Now the language tag */
+ prefix_length += 3;
+ language_offset = prefix_length;
- 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 (; prefix_length < length && buffer[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
- for (lang_key = lang; *lang_key; lang_key++)
- /* Empty loop */ ;
+ /* WARNING: the length may be invalid here, this is checked below. */
+ translated_keyword_offset = ++prefix_length;
- lang_key++; /* Skip NUL separator */
+ for (; prefix_length < length && buffer[prefix_length] != 0;
+ ++prefix_length)
+ /* Empty loop */ ;
- 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;
- }
+ /* 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 allocation may overflow.
+ */
+ ++prefix_length;
- for (text = lang_key; *text; text++)
- /* Empty loop */ ;
+ if (compressed == 0 && prefix_length <= length)
+ uncompressed_length = length - prefix_length;
- text++; /* Skip NUL separator */
+ else if (compressed != 0 && prefix_length < length)
+ {
+ uncompressed_length = PNG_SIZE_MAX;
- 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;
- }
+ /* 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.
+ */
+ if (png_decompress_chunk(png_ptr, length, prefix_length,
+ &uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
+ buffer = png_ptr->read_buffer;
- prefix_len = text - png_ptr->chunkdata;
+ else
+ errmsg = png_ptr->zstream.msg;
+ }
- key=png_ptr->chunkdata;
+ else
+ errmsg = "truncated";
- if (comp_flag)
- png_decompress_chunk(png_ptr, comp_type,
- (size_t)length, prefix_len, &data_len);
+ if (errmsg == NULL)
+ {
+ png_text text;
- else
- data_len = png_strlen(png_ptr->chunkdata + prefix_len);
+ buffer[uncompressed_length+prefix_length] = 0;
- text_ptr = (png_textp)png_malloc_warn(png_ptr,
- png_sizeof(png_text));
+ if (compressed == 0)
+ text.compression = PNG_ITXT_COMPRESSION_NONE;
- 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;
- }
+ else
+ text.compression = PNG_ITXT_COMPRESSION_zTXt;
- 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;
+ text.key = (png_charp)buffer;
+ text.lang = (png_charp)buffer + language_offset;
+ text.lang_key = (png_charp)buffer + translated_keyword_offset;
+ text.text = (png_charp)buffer + prefix_length;
+ text.text_length = 0;
+ text.itxt_length = uncompressed_length;
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+ if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0)
+ errmsg = "insufficient memory";
+ }
+ }
- png_free(png_ptr, text_ptr);
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
+ else
+ errmsg = "bad compression info";
- if (ret)
- png_error(png_ptr, "Insufficient memory to store iTXt chunk");
+ if (errmsg != NULL)
+ png_chunk_benign_error(png_ptr, errmsg);
}
#endif
-/* This function is called when we haven't found a handler for a
- * chunk. If there isn't a problem with the chunk itself (ie bad
- * chunk name, CRC, or a critical chunk), the chunk is silently ignored
- * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
- * case it will be saved away to be written out later.
- */
-void /* PRIVATE */
-png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */
+static int
+png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length)
{
- png_uint_32 skip = 0;
+ png_alloc_size_t limit = PNG_SIZE_MAX;
- png_debug(1, "in png_handle_unknown");
+ if (png_ptr->unknown_chunk.data != NULL)
+ {
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+ }
-#ifdef PNG_USER_LIMITS_SUPPORTED
- if (png_ptr->user_chunk_cache_max != 0)
+# 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
+
+ if (length <= limit)
{
- if (png_ptr->user_chunk_cache_max == 1)
- {
- png_crc_finish(png_ptr, length);
- return;
- }
+ PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
+ /* The following is safe because of the PNG_SIZE_MAX init above */
+ png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/;
+ /* 'mode' is a flag array, only the bottom four bits matter here */
+ png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/;
- if (--png_ptr->user_chunk_cache_max == 1)
+ if (length == 0)
+ png_ptr->unknown_chunk.data = NULL;
+
+ else
{
- png_warning(png_ptr, "No space in chunk cache for unknown chunk");
- png_crc_finish(png_ptr, length);
- return;
+ /* Do a 'warn' here - it is handled below. */
+ png_ptr->unknown_chunk.data = png_voidcast(png_bytep,
+ png_malloc_warn(png_ptr, length));
}
}
-#endif
- if (png_ptr->mode & PNG_HAVE_IDAT)
+ if (png_ptr->unknown_chunk.data == NULL && length > 0)
{
- if (png_ptr->chunk_name != png_IDAT)
- png_ptr->mode |= PNG_AFTER_IDAT;
+ /* This is benign because we clean up correctly */
+ png_crc_finish(png_ptr, length);
+ png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits");
+ return 0;
}
- if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
+ else
{
-#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
- if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS
-#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
- && png_ptr->read_user_chunk_fn == NULL
-#endif
- )
-#endif
- png_chunk_error(png_ptr, "unknown critical chunk");
+ if (length > 0)
+ png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);
+ png_crc_finish(png_ptr, 0);
+ return 1;
}
+}
+#endif /* READ_UNKNOWN_CHUNKS */
+
+/* Handle an unknown, or known but disabled, chunk */
+void /* PRIVATE */
+png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr,
+ png_uint_32 length, int keep)
+{
+ int handled = 0; /* the chunk was handled */
+
+ png_debug(1, "in png_handle_unknown");
#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 > 65535)
- {
- png_warning(png_ptr, "unknown chunk too large to fit in memory");
- skip = length - 65535;
- length = 65535;
- }
-#endif
+ /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing
+ * the bug which meant that setting a non-default behavior for a specific
+ * chunk would be ignored (the default was always used unless a user
+ * callback was installed).
+ *
+ * 'keep' is the value from the png_chunk_unknown_handling, the setting for
+ * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it
+ * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here.
+ * This is just an optimization to avoid multiple calls to the lookup
+ * function.
+ */
+# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name);
+# endif
+# endif
- /* TODO: this code is very close to the unknown handling in pngpread.c,
- * maybe it can be put into a common utility routine?
- * png_struct::unknown_chunk is just used as a temporary variable, along
- * with the data into which the chunk is read. These can be eliminated.
+ /* One of the following methods will read the chunk or skip it (at least one
+ * of these is always defined because this is the only way to switch on
+ * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ */
+# ifdef PNG_READ_USER_CHUNKS_SUPPORTED
+ /* The user callback takes precedence over the chunk keep value, but the
+ * keep value is still required to validate a save of a critical chunk.
*/
- PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
- png_ptr->unknown_chunk.size = (png_size_t)length;
+ if (png_ptr->read_user_chunk_fn != NULL)
+ {
+ if (png_cache_unknown_chunk(png_ptr, length) != 0)
+ {
+ /* Callback to user unknown chunk handler */
+ int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr,
+ &png_ptr->unknown_chunk);
+
+ /* ret is:
+ * negative: An error occurred; png_chunk_error will be called.
+ * zero: The chunk was not handled, the chunk will be discarded
+ * unless png_set_keep_unknown_chunks has been used to set
+ * a 'keep' behavior for this particular chunk, in which
+ * case that will be used. A critical chunk will cause an
+ * error at this point unless it is to be saved.
+ * positive: The chunk was handled, libpng will ignore/discard it.
+ */
+ if (ret < 0)
+ png_chunk_error(png_ptr, "error in user chunk");
- if (length == 0)
- png_ptr->unknown_chunk.data = NULL;
+ else if (ret == 0)
+ {
+ /* If the keep value is 'default' or 'never' override it, but
+ * still error out on critical chunks unless the keep value is
+ * 'always' While this is weird it is the behavior in 1.4.12.
+ * A possible improvement would be to obey the value set for the
+ * chunk, but this would be an API change that would probably
+ * damage some applications.
+ *
+ * The png_app_warning below catches the case that matters, where
+ * the application has not set specific save or ignore for this
+ * chunk or global save or ignore.
+ */
+ if (keep < PNG_HANDLE_CHUNK_IF_SAFE)
+ {
+# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
+ if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE)
+ {
+ png_chunk_warning(png_ptr, "Saving unknown chunk:");
+ png_app_warning(png_ptr,
+ "forcing save of an unhandled chunk;"
+ " please call png_set_keep_unknown_chunks");
+ /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */
+ }
+# endif
+ keep = PNG_HANDLE_CHUNK_IF_SAFE;
+ }
+ }
+
+ else /* chunk was handled */
+ {
+ handled = 1;
+ /* Critical chunks can be safely discarded at this point. */
+ keep = PNG_HANDLE_CHUNK_NEVER;
+ }
+ }
+
+ else
+ keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */
+ }
else
+ /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */
+# endif /* READ_USER_CHUNKS */
+
+# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
{
- png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
- png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);
+ /* keep is currently just the per-chunk setting, if there was no
+ * setting change it to the global default now (not that this may
+ * still be AS_DEFAULT) then obtain the cache of the chunk if required,
+ * if not simply skip the chunk.
+ */
+ if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT)
+ keep = png_ptr->unknown_default;
+
+ if (keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (keep == PNG_HANDLE_CHUNK_IF_SAFE &&
+ PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))
+ {
+ if (png_cache_unknown_chunk(png_ptr, length) == 0)
+ keep = PNG_HANDLE_CHUNK_NEVER;
+ }
+
+ else
+ png_crc_finish(png_ptr, length);
}
+# else
+# ifndef PNG_READ_USER_CHUNKS_SUPPORTED
+# error no method to support READ_UNKNOWN_CHUNKS
+# endif
-#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);
+ /* If here there is no read callback pointer set and no support is
+ * compiled in to just save the unknown chunks, so simply skip this
+ * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then
+ * the app has erroneously asked for unknown chunk saving when there
+ * is no support.
+ */
+ if (keep > PNG_HANDLE_CHUNK_NEVER)
+ png_app_error(png_ptr, "no unknown chunk support available");
- if (ret < 0)
- png_chunk_error(png_ptr, "error in user chunk");
+ png_crc_finish(png_ptr, length);
+ }
+# endif
- if (ret == 0)
+# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
+ /* Now store the chunk in the chunk list if appropriate, and if the limits
+ * permit it.
+ */
+ if (keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (keep == PNG_HANDLE_CHUNK_IF_SAFE &&
+ PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)))
+ {
+# ifdef PNG_USER_LIMITS_SUPPORTED
+ switch (png_ptr->user_chunk_cache_max)
{
- if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
- {
-#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
- if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS)
-#endif
- png_chunk_error(png_ptr, "unknown critical chunk");
- }
+ case 2:
+ png_ptr->user_chunk_cache_max = 1;
+ png_chunk_benign_error(png_ptr, "no space in chunk cache");
+ /* FALL THROUGH */
+ case 1:
+ /* NOTE: prior to 1.6.0 this case resulted in an unknown critical
+ * chunk being skipped, now there will be a hard error below.
+ */
+ break;
- png_set_unknown_chunks(png_ptr, info_ptr,
- &png_ptr->unknown_chunk, 1);
+ default: /* not at limit */
+ --(png_ptr->user_chunk_cache_max);
+ /* FALL THROUGH */
+ case 0: /* no limit */
+# endif /* USER_LIMITS */
+ /* Here when the limit isn't reached or when limits are compiled
+ * out; store the chunk.
+ */
+ png_set_unknown_chunks(png_ptr, info_ptr,
+ &png_ptr->unknown_chunk, 1);
+ handled = 1;
+# ifdef PNG_USER_LIMITS_SUPPORTED
+ break;
}
+# endif
}
+# else /* no store support: the chunk must be handled by the user callback */
+ PNG_UNUSED(info_ptr)
+# endif
- else
-#endif
- png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
-
+ /* Regardless of the error handling below the cached data (if any) can be
+ * freed now. Notice that the data is not freed if there is a png_error, but
+ * it will be freed by destroy_read_struct.
+ */
+ if (png_ptr->unknown_chunk.data != NULL)
png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
- }
-
- else
-#endif
- skip = length;
+ png_ptr->unknown_chunk.data = NULL;
- png_crc_finish(png_ptr, skip);
+#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */
+ /* There is no support to read an unknown chunk, so just skip it. */
+ png_crc_finish(png_ptr, length);
+ PNG_UNUSED(info_ptr)
+ PNG_UNUSED(keep)
+#endif /* !READ_UNKNOWN_CHUNKS */
-#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
- PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
-#endif
+ /* Check for unhandled critical chunks */
+ if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
+ png_chunk_error(png_ptr, "unhandled critical chunk");
}
/* This function is called to verify that a chunk name is valid.
@@ -2757,7 +2976,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_uint_32 chunk_name)
+png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name)
{
int i;
@@ -2782,11 +3001,11 @@ png_check_chunk_name(png_structp png_ptr, png_uint_32 chunk_name)
* 'display' is false only those pixels present in the pass are filled in.
*/
void /* PRIVATE */
-png_combine_row(png_structp png_ptr, png_bytep dp, int display)
+png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display)
{
unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
png_const_bytep sp = png_ptr->row_buf + 1;
- png_uint_32 row_width = png_ptr->width;
+ png_alloc_size_t row_width = png_ptr->width;
unsigned int pass = png_ptr->pass;
png_bytep end_ptr = 0;
png_byte end_byte = 0;
@@ -2823,7 +3042,8 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;
end_byte = *end_ptr;
# ifdef PNG_READ_PACKSWAP_SUPPORTED
- if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
+ /* little-endian byte */
end_mask = 0xff << end_mask;
else /* big-endian byte */
@@ -2832,17 +3052,18 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* end_mask is now the bits to *keep* from the destination row */
}
- /* For non-interlaced images this reduces to a png_memcpy(). A png_memcpy()
+ /* For non-interlaced images this reduces to a memcpy(). A memcpy()
* will also happen if interlacing isn't supported or if the application
* does not call png_set_interlace_handling(). In the latter cases the
* caller just gets a sequence of the unexpanded rows from each interlace
* pass.
*/
#ifdef PNG_READ_INTERLACING_SUPPORTED
- if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) &&
- pass < 6 && (display == 0 ||
- /* The following copies everything for 'display' on passes 0, 2 and 4. */
- (display == 1 && (pass & 1) != 0)))
+ if (png_ptr->interlaced != 0 &&
+ (png_ptr->transformations & PNG_INTERLACE) != 0 &&
+ pass < 6 && (display == 0 ||
+ /* The following copies everything for 'display' on passes 0, 2 and 4. */
+ (display == 1 && (pass & 1) != 0)))
{
/* Narrow images may have no bits in a pass; the caller should handle
* this, but this test is cheap:
@@ -2938,7 +3159,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\
S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }
-# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) }
+# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) }
# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
@@ -2974,10 +3195,10 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
*/
# define MASK(pass,depth,display,png)\
((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))
-#endif /* !PNG_USE_COMPILE_TIME_MASKS */
+#endif /* !USE_COMPILE_TIME_MASKS */
/* Use the appropriate mask to copy the required bits. In some cases
- * the byte mask will be 0 or 0xff, optimize these cases. row_width is
+ * the byte mask will be 0 or 0xff; optimize these cases. row_width is
* the number of pixels, but the code copies bytes, so it is necessary
* to special case the end.
*/
@@ -2985,7 +3206,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
png_uint_32 mask;
# ifdef PNG_READ_PACKSWAP_SUPPORTED
- if (png_ptr->transformations & PNG_PACKSWAP)
+ if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
mask = MASK(pass, pixel_depth, display, 0);
else
@@ -3049,7 +3270,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
}
/* Work out the bytes to copy. */
- if (display)
+ if (display != 0)
{
/* When doing the 'block' algorithm the pixel in the pass gets
* replicated to adjacent pixels. This is why the even (0,2,4,6)
@@ -3059,7 +3280,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* But don't allow this number to exceed the actual row width. */
if (bytes_to_copy > row_width)
- bytes_to_copy = row_width;
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
}
else /* normal row; Adam7 only ever gives us one pixel to copy. */
@@ -3116,7 +3337,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* This can only be the RGB case, so each copy is exactly one
* pixel and it is not necessary to check for a partial copy.
*/
- for(;;)
+ for (;;)
{
dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2];
@@ -3133,26 +3354,27 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* Check for double byte alignment and, if possible, use a
* 16-bit copy. Don't attempt this for narrow images - ones that
* are less than an interlace panel wide. Don't attempt it for
- * wide bytes_to_copy either - use the png_memcpy there.
+ * wide bytes_to_copy either - use the memcpy there.
*/
- if (bytes_to_copy < 16 /*else use png_memcpy*/ &&
- png_isaligned(dp, png_uint_16) &&
- png_isaligned(sp, png_uint_16) &&
- bytes_to_copy % sizeof (png_uint_16) == 0 &&
- bytes_to_jump % sizeof (png_uint_16) == 0)
+ if (bytes_to_copy < 16 /*else use memcpy*/ &&
+ png_isaligned(dp, png_uint_16) &&
+ png_isaligned(sp, png_uint_16) &&
+ bytes_to_copy % (sizeof (png_uint_16)) == 0 &&
+ bytes_to_jump % (sizeof (png_uint_16)) == 0)
{
/* Everything is aligned for png_uint_16 copies, but try for
* png_uint_32 first.
*/
- if (png_isaligned(dp, png_uint_32) &&
- png_isaligned(sp, png_uint_32) &&
- bytes_to_copy % sizeof (png_uint_32) == 0 &&
- bytes_to_jump % sizeof (png_uint_32) == 0)
+ if (png_isaligned(dp, png_uint_32) != 0 &&
+ png_isaligned(sp, png_uint_32) != 0 &&
+ bytes_to_copy % (sizeof (png_uint_32)) == 0 &&
+ bytes_to_jump % (sizeof (png_uint_32)) == 0)
{
- png_uint_32p dp32 = (png_uint_32p)dp;
- png_const_uint_32p sp32 = (png_const_uint_32p)sp;
- unsigned int skip = (bytes_to_jump-bytes_to_copy) /
- sizeof (png_uint_32);
+ png_uint_32p dp32 = png_aligncast(png_uint_32p,dp);
+ png_const_uint_32p sp32 = png_aligncastconst(
+ png_const_uint_32p, sp);
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
+ (sizeof (png_uint_32));
do
{
@@ -3160,7 +3382,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
do
{
*dp32++ = *sp32++;
- c -= sizeof (png_uint_32);
+ c -= (sizeof (png_uint_32));
}
while (c > 0);
@@ -3190,10 +3412,11 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
*/
else
{
- png_uint_16p dp16 = (png_uint_16p)dp;
- png_const_uint_16p sp16 = (png_const_uint_16p)sp;
- unsigned int skip = (bytes_to_jump-bytes_to_copy) /
- sizeof (png_uint_16);
+ png_uint_16p dp16 = png_aligncast(png_uint_16p, dp);
+ png_const_uint_16p sp16 = png_aligncastconst(
+ png_const_uint_16p, sp);
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
+ (sizeof (png_uint_16));
do
{
@@ -3201,7 +3424,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
do
{
*dp16++ = *sp16++;
- c -= sizeof (png_uint_16);
+ c -= (sizeof (png_uint_16));
}
while (c > 0);
@@ -3223,12 +3446,12 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
return;
}
}
-#endif /* PNG_ALIGN_ code */
+#endif /* ALIGN_TYPE code */
- /* The true default - use a png_memcpy: */
+ /* The true default - use a memcpy: */
for (;;)
{
- png_memcpy(dp, sp, bytes_to_copy);
+ memcpy(dp, sp, bytes_to_copy);
if (row_width <= bytes_to_jump)
return;
@@ -3237,7 +3460,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
dp += bytes_to_jump;
row_width -= bytes_to_jump;
if (bytes_to_copy > row_width)
- bytes_to_copy = row_width;
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
}
}
@@ -3247,13 +3470,13 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* Here if pixel_depth < 8 to check 'end_ptr' below. */
}
else
-#endif
+#endif /* READ_INTERLACING */
- /* If here then the switch above wasn't used so just png_memcpy the whole row
+ /* If here then the switch above wasn't used so just memcpy the whole row
* from the temporary row buffer (notice that this overwrites the end of the
* destination row if it is a partial byte.)
*/
- png_memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
+ memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
/* Restore the overwritten bits from the last byte if necessary. */
if (end_ptr != NULL)
@@ -3290,7 +3513,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
int j;
#ifdef PNG_READ_PACKSWAP_SUPPORTED
- if (transformations & PNG_PACKSWAP)
+ if ((transformations & PNG_PACKSWAP) != 0)
{
sshift = (int)((row_info->width + 7) & 0x07);
dshift = (int)((final_width + 7) & 0x07);
@@ -3314,8 +3537,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
v = (png_byte)((*sp >> sshift) & 0x01);
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));
+ tmp |= v << dshift;
+ *dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
@@ -3349,7 +3573,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
png_uint_32 i;
#ifdef PNG_READ_PACKSWAP_SUPPORTED
- if (transformations & PNG_PACKSWAP)
+ if ((transformations & PNG_PACKSWAP) != 0)
{
sshift = (int)(((row_info->width + 3) & 0x03) << 1);
dshift = (int)(((final_width + 3) & 0x03) << 1);
@@ -3376,8 +3600,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
v = (png_byte)((*sp >> sshift) & 0x03);
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));
+ tmp |= v << dshift;
+ *dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
@@ -3411,7 +3636,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
int jstop = png_pass_inc[pass];
#ifdef PNG_READ_PACKSWAP_SUPPORTED
- if (transformations & PNG_PACKSWAP)
+ if ((transformations & PNG_PACKSWAP) != 0)
{
sshift = (int)(((row_info->width + 1) & 0x01) << 2);
dshift = (int)(((final_width + 1) & 0x01) << 2);
@@ -3437,8 +3662,9 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
for (j = 0; j < jstop; j++)
{
- *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
- *dp |= (png_byte)(v << dshift);
+ unsigned int tmp = *dp & (0xf0f >> (4 - dshift));
+ tmp |= v << dshift;
+ *dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
@@ -3476,14 +3702,14 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
for (i = 0; i < row_info->width; i++)
{
- png_byte v[8];
+ png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */
int j;
- png_memcpy(v, sp, pixel_bytes);
+ memcpy(v, sp, pixel_bytes);
for (j = 0; j < jstop; j++)
{
- png_memcpy(dp, v, pixel_bytes);
+ memcpy(dp, v, pixel_bytes);
dp -= pixel_bytes;
}
@@ -3500,7 +3726,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
PNG_UNUSED(transformations) /* Silence compiler warning */
#endif
}
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
+#endif /* READ_INTERLACING */
static void
png_read_filter_row_sub(png_row_infop row_info, png_bytep row,
@@ -3654,74 +3880,22 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
if (pb < pa) pa = pb, a = b;
if (pc < pa) a = c;
- c = b;
a += *row;
*row++ = (png_byte)a;
}
}
-#ifdef PNG_ARM_NEON
-
-#ifdef __linux__
-#include <stdio.h>
-#include <elf.h>
-#include <asm/hwcap.h>
-
-static int png_have_hwcap(unsigned cap)
-{
- FILE *f = fopen("/proc/self/auxv", "r");
- Elf32_auxv_t aux;
- int have_cap = 0;
-
- if (!f)
- return 0;
-
- while (fread(&aux, sizeof(aux), 1, f) > 0)
- {
- if (aux.a_type == AT_HWCAP &&
- aux.a_un.a_val & cap)
- {
- have_cap = 1;
- break;
- }
- }
-
- fclose(f);
-
- return have_cap;
-}
-#endif /* __linux__ */
-
static void
-png_init_filter_functions_neon(png_structp pp, unsigned int bpp)
-{
-#ifdef __linux__
- if (!png_have_hwcap(HWCAP_NEON))
- return;
-#endif
-
- pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;
-
- if (bpp == 3)
- {
- pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;
- pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;
- pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
- png_read_filter_row_paeth3_neon;
- }
-
- else if (bpp == 4)
- {
- pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
- pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
- pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
- png_read_filter_row_paeth4_neon;
- }
-}
-#endif /* PNG_ARM_NEON */
-
-static void
-png_init_filter_functions(png_structp pp)
+png_init_filter_functions(png_structrp pp)
+ /* This function is called once for every PNG image (except for PNG images
+ * that only use PNG_FILTER_VALUE_NONE for all rows) to set the
+ * implementations required to reverse the filtering of PNG rows. Reversing
+ * the filter is the first transformation performed on the row data. It is
+ * performed in place, therefore an implementation can be selected based on
+ * the image pixel format. If the implementation depends on image width then
+ * take care to ensure that it works correctly if the image is interlaced -
+ * interlacing causes the actual row width to vary.
+ */
{
unsigned int bpp = (pp->pixel_depth + 7) >> 3;
@@ -3735,26 +3909,217 @@ png_init_filter_functions(png_structp pp)
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
png_read_filter_row_paeth_multibyte_pixel;
-#ifdef PNG_ARM_NEON
- png_init_filter_functions_neon(pp, bpp);
+#ifdef PNG_FILTER_OPTIMIZATIONS
+ /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to
+ * call to install hardware optimizations for the above functions; simply
+ * replace whatever elements of the pp->read_filter[] array with a hardware
+ * specific (or, for that matter, generic) optimization.
+ *
+ * To see an example of this examine what configure.ac does when
+ * --enable-arm-neon is specified on the command line.
+ */
+ PNG_FILTER_OPTIMIZATIONS(pp, bpp);
#endif
}
void /* PRIVATE */
-png_read_filter_row(png_structp pp, png_row_infop row_info, png_bytep row,
+png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row,
png_const_bytep prev_row, int filter)
{
- if (pp->read_filter[0] == NULL)
- png_init_filter_functions(pp);
+ /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define
+ * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic
+ * implementations. See png_init_filter_functions above.
+ */
if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
+ {
+ if (pp->read_filter[0] == NULL)
+ png_init_filter_functions(pp);
+
pp->read_filter[filter-1](row_info, row, prev_row);
+ }
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
void /* PRIVATE */
-png_read_finish_row(png_structp png_ptr)
+png_read_IDAT_data(png_structrp png_ptr, png_bytep output,
+ png_alloc_size_t avail_out)
+{
+ /* Loop reading IDATs and decompressing the result into output[avail_out] */
+ png_ptr->zstream.next_out = output;
+ png_ptr->zstream.avail_out = 0; /* safety: set below */
+
+ if (output == NULL)
+ avail_out = 0;
+
+ do
+ {
+ int ret;
+ png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
+
+ if (png_ptr->zstream.avail_in == 0)
+ {
+ uInt avail_in;
+ png_bytep buffer;
+
+ while (png_ptr->idat_size == 0)
+ {
+ png_crc_finish(png_ptr, 0);
+
+ png_ptr->idat_size = png_read_chunk_header(png_ptr);
+ /* This is an error even in the 'check' case because the code just
+ * consumed a non-IDAT header.
+ */
+ if (png_ptr->chunk_name != png_IDAT)
+ png_error(png_ptr, "Not enough image data");
+ }
+
+ avail_in = png_ptr->IDAT_read_size;
+
+ if (avail_in > png_ptr->idat_size)
+ avail_in = (uInt)png_ptr->idat_size;
+
+ /* A PNG with a gradually increasing IDAT size will defeat this attempt
+ * to minimize memory usage by causing lots of re-allocs, but
+ * realistically doing IDAT_read_size re-allocs is not likely to be a
+ * big problem.
+ */
+ buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/);
+
+ png_crc_read(png_ptr, buffer, avail_in);
+ png_ptr->idat_size -= avail_in;
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = avail_in;
+ }
+
+ /* And set up the output side. */
+ if (output != NULL) /* standard read */
+ {
+ uInt out = ZLIB_IO_MAX;
+
+ if (out > avail_out)
+ out = (uInt)avail_out;
+
+ avail_out -= out;
+ png_ptr->zstream.avail_out = out;
+ }
+
+ else /* after last row, checking for end */
+ {
+ png_ptr->zstream.next_out = tmpbuf;
+ png_ptr->zstream.avail_out = (sizeof tmpbuf);
+ }
+
+ /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the
+ * process. If the LZ stream is truncated the sequential reader will
+ * terminally damage the stream, above, by reading the chunk header of the
+ * following chunk (it then exits with png_error).
+ *
+ * TODO: deal more elegantly with truncated IDAT lists.
+ */
+ ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
+
+ /* Take the unconsumed output back. */
+ if (output != NULL)
+ avail_out += png_ptr->zstream.avail_out;
+
+ else /* avail_out counts the extra bytes */
+ avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out;
+
+ png_ptr->zstream.avail_out = 0;
+
+ if (ret == Z_STREAM_END)
+ {
+ /* Do this for safety; we won't read any more into this row. */
+ png_ptr->zstream.next_out = NULL;
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+
+ if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0)
+ png_chunk_benign_error(png_ptr, "Extra compressed data");
+ break;
+ }
+
+ if (ret != Z_OK)
+ {
+ png_zstream_error(png_ptr, ret);
+
+ if (output != NULL)
+ png_chunk_error(png_ptr, png_ptr->zstream.msg);
+
+ else /* checking */
+ {
+ png_chunk_benign_error(png_ptr, png_ptr->zstream.msg);
+ return;
+ }
+ }
+ } while (avail_out > 0);
+
+ if (avail_out > 0)
+ {
+ /* The stream ended before the image; this is the same as too few IDATs so
+ * should be handled the same way.
+ */
+ if (output != NULL)
+ png_error(png_ptr, "Not enough image data");
+
+ else /* the deflate stream contained extra data */
+ png_chunk_benign_error(png_ptr, "Too much image data");
+ }
+}
+
+void /* PRIVATE */
+png_read_finish_IDAT(png_structrp png_ptr)
+{
+ /* We don't need any more data and the stream should have ended, however the
+ * LZ end code may actually not have been processed. In this case we must
+ * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk
+ * may still remain to be consumed.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ {
+ /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in
+ * the compressed stream, but the stream may be damaged too, so even after
+ * this call we may need to terminate the zstream ownership.
+ */
+ png_read_IDAT_data(png_ptr, NULL, 0);
+ png_ptr->zstream.next_out = NULL; /* safety */
+
+ /* Now clear everything out for safety; the following may not have been
+ * done.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0)
+ {
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED;
+ }
+ }
+
+ /* If the zstream has not been released do it now *and* terminate the reading
+ * of the final IDAT chunk.
+ */
+ if (png_ptr->zowner == png_IDAT)
+ {
+ /* Always do this; the pointers otherwise point into the read buffer. */
+ png_ptr->zstream.next_in = NULL;
+ png_ptr->zstream.avail_in = 0;
+
+ /* Now we no longer own the zstream. */
+ png_ptr->zowner = 0;
+
+ /* The slightly weird semantics of the sequential IDAT reading is that we
+ * are always in or at the end of an IDAT chunk, so we always need to do a
+ * crc_finish here. If idat_size is non-zero we also need to read the
+ * spurious bytes at the end of the chunk now.
+ */
+ (void)png_crc_finish(png_ptr, png_ptr->idat_size);
+ }
+}
+
+void /* PRIVATE */
+png_read_finish_row(png_structrp png_ptr)
{
-#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
@@ -3768,22 +4133,20 @@ png_read_finish_row(png_structp png_ptr)
/* Offset to next interlace block in the y direction */
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
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)
+ if (png_ptr->interlaced != 0)
{
png_ptr->row_number = 0;
/* TO DO: don't do this if prev_row isn't needed (requires
* read-ahead of the next row's filter byte.
*/
- png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
do
{
@@ -3797,7 +4160,7 @@ png_read_finish_row(png_structp png_ptr)
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
- if (!(png_ptr->transformations & PNG_INTERLACE))
+ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
{
png_ptr->num_rows = (png_ptr->height +
png_pass_yinc[png_ptr->pass] - 1 -
@@ -3813,80 +4176,15 @@ 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))
- {
- char extra;
- int ret;
-
- png_ptr->zstream.next_out = (Byte *)&extra;
- png_ptr->zstream.avail_out = (uInt)1;
-
- for (;;)
- {
- if (!(png_ptr->zstream.avail_in))
- {
- while (!png_ptr->idat_size)
- {
- png_crc_finish(png_ptr, 0);
- png_ptr->idat_size = png_read_chunk_header(png_ptr);
- if (png_ptr->chunk_name != png_IDAT)
- png_error(png_ptr, "Not enough image data");
- }
-
- png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
- 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_ptr->zstream.avail_in);
- png_ptr->idat_size -= png_ptr->zstream.avail_in;
- }
-
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
-
- if (ret == Z_STREAM_END)
- {
- if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
- png_ptr->idat_size)
- png_warning(png_ptr, "Extra compressed data");
-
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
-
- if (ret != Z_OK)
- png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
- "Decompression Error");
-
- if (!(png_ptr->zstream.avail_out))
- {
- png_warning(png_ptr, "Extra compressed data");
- png_ptr->mode |= PNG_AFTER_IDAT;
- png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
- break;
- }
-
- }
- png_ptr->zstream.avail_out = 0;
- }
-
- if (png_ptr->idat_size || png_ptr->zstream.avail_in)
- png_warning(png_ptr, "Extra compression data");
- inflateReset(&png_ptr->zstream);
-
- png_ptr->mode |= PNG_AFTER_IDAT;
+ /* Here after at the end of the last row of the last pass. */
+ png_read_finish_IDAT(png_ptr);
}
-#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
+#endif /* SEQUENTIAL_READ */
void /* PRIVATE */
-png_read_start_row(png_structp png_ptr)
+png_read_start_row(png_structrp png_ptr)
{
-#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
@@ -3900,20 +4198,18 @@ png_read_start_row(png_structp png_ptr)
/* Offset to next interlace block in the y direction */
static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
-#endif
int max_pixel_depth;
png_size_t row_bytes;
png_debug(1, "in png_read_start_row");
- png_ptr->zstream.avail_in = 0;
+
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
png_init_read_transformations(png_ptr);
#endif
-#ifdef PNG_READ_INTERLACING_SUPPORTED
- if (png_ptr->interlaced)
+ if (png_ptr->interlaced != 0)
{
- if (!(png_ptr->transformations & PNG_INTERLACE))
+ if ((png_ptr->transformations & PNG_INTERLACE) == 0)
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
png_pass_ystart[0]) / png_pass_yinc[0];
@@ -3927,7 +4223,6 @@ png_read_start_row(png_structp png_ptr)
}
else
-#endif /* PNG_READ_INTERLACING_SUPPORTED */
{
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = png_ptr->width;
@@ -3935,7 +4230,7 @@ png_read_start_row(png_structp png_ptr)
max_pixel_depth = png_ptr->pixel_depth;
- /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of
+ /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of
* calculations to calculate the final pixel depth, then
* png_do_read_transforms actually does the transforms. This means that the
* code which effectively calculates this value is actually repeated in three
@@ -3946,16 +4241,16 @@ png_read_start_row(png_structp png_ptr)
* TODO: fix this.
*/
#ifdef PNG_READ_PACK_SUPPORTED
- if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8)
max_pixel_depth = 8;
#endif
#ifdef PNG_READ_EXPAND_SUPPORTED
- if (png_ptr->transformations & PNG_EXPAND)
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
max_pixel_depth = 32;
else
@@ -3967,13 +4262,13 @@ png_read_start_row(png_structp png_ptr)
if (max_pixel_depth < 8)
max_pixel_depth = 8;
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
max_pixel_depth *= 2;
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
- if (png_ptr->num_trans)
+ if (png_ptr->num_trans != 0)
{
max_pixel_depth *= 4;
max_pixel_depth /= 3;
@@ -3983,13 +4278,13 @@ png_read_start_row(png_structp png_ptr)
#endif
#ifdef PNG_READ_EXPAND_16_SUPPORTED
- if (png_ptr->transformations & PNG_EXPAND_16)
+ if ((png_ptr->transformations & PNG_EXPAND_16) != 0)
{
# ifdef PNG_READ_EXPAND_SUPPORTED
/* In fact it is an error if it isn't supported, but checking is
* the safe way.
*/
- if (png_ptr->transformations & PNG_EXPAND)
+ if ((png_ptr->transformations & PNG_EXPAND) != 0)
{
if (png_ptr->bit_depth < 16)
max_pixel_depth *= 2;
@@ -4001,7 +4296,7 @@ png_read_start_row(png_structp png_ptr)
#endif
#ifdef PNG_READ_FILLER_SUPPORTED
- if (png_ptr->transformations & (PNG_FILLER))
+ if ((png_ptr->transformations & (PNG_FILLER)) != 0)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
@@ -4025,14 +4320,15 @@ png_read_start_row(png_structp png_ptr)
#endif
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
- if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
{
if (
#ifdef PNG_READ_EXPAND_SUPPORTED
- (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+ (png_ptr->num_trans != 0 &&
+ (png_ptr->transformations & PNG_EXPAND) != 0) ||
#endif
#ifdef PNG_READ_FILLER_SUPPORTED
- (png_ptr->transformations & (PNG_FILLER)) ||
+ (png_ptr->transformations & (PNG_FILLER)) != 0 ||
#endif
png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
@@ -4065,7 +4361,7 @@ 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) != 0)
{
int user_pixel_depth = png_ptr->user_transform_depth *
png_ptr->user_transform_channels;
@@ -4101,7 +4397,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_free(png_ptr, png_ptr->big_row_buf);
png_free(png_ptr, png_ptr->big_prev_row);
- if (png_ptr->interlaced)
+ if (png_ptr->interlaced != 0)
png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
row_bytes + 48);
@@ -4144,7 +4440,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
png_error(png_ptr, "Row has too many bytes to allocate in memory");
- png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
png_debug1(3, "width = %u,", png_ptr->width);
png_debug1(3, "height = %u,", png_ptr->height);
@@ -4154,6 +4450,27 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
png_debug1(3, "irowbytes = %lu",
(unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
+ /* The sequential reader needs a buffer for IDAT, but the progressive reader
+ * does not, so free the read buffer now regardless; the sequential reader
+ * reallocates it on demand.
+ */
+ if (png_ptr->read_buffer != 0)
+ {
+ png_bytep buffer = png_ptr->read_buffer;
+
+ png_ptr->read_buffer_size = 0;
+ png_ptr->read_buffer = NULL;
+ png_free(png_ptr, buffer);
+ }
+
+ /* Finally claim the zstream for the inflate of the IDAT data, use the bits
+ * value from the stream (note that this will result in a fatal error if the
+ * IDAT stream has a bogus deflate header window_bits value, but this should
+ * not be happening any longer!)
+ */
+ if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg);
+
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
-#endif /* PNG_READ_SUPPORTED */
+#endif /* READ */