libpng/pngrutil.c
John Bowler 4a6c6df6c7 [libpng16] Allow fine grain control of unknown chunk APIs. This change allows
png_set_keep_unknown_chunks() to be turned off if not required and causes
both read and write to behave appropriately (on read this is only possible
if the user callback is used to handle unknown chunks).  The change
also removes the support for storing unknown chunks in the info_struct
if the only unknown handling enabled is via the callback, allowing libpng
to be configured with callback reading and none of the unnecessary code.
2012-08-16 16:12:13 -05:00

4530 lines
138 KiB
C

/* pngrutil.c - utilities to read a PNG file
*
* Last changed in libpng 1.6.0 [(PENDING RELEASE)]
* Copyright (c) 1998-2012 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
* This file contains routines that are only called from within
* libpng itself during the course of reading an image.
*/
#include "pngpriv.h"
#ifdef PNG_READ_SUPPORTED
#define png_strtod(p,a,b) strtod(a,b)
png_uint_32 PNGAPI
png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
if (uval > PNG_UINT_31_MAX)
png_error(png_ptr, "PNG unsigned integer out of range");
return (uval);
}
#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
/* The following is a variation on the above for use with the fixed
* point values used for gAMA and cHRM. Instead of png_error it
* issues a warning and returns (-1) - an invalid value because both
* gAMA and cHRM use *unsigned* integers for fixed point values.
*/
#define PNG_FIXED_ERROR (-1)
static png_fixed_point /* PRIVATE */
png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
if (uval <= PNG_UINT_31_MAX)
return (png_fixed_point)uval; /* known to be in range */
/* The caller can turn off the warning by passing NULL. */
if (png_ptr != NULL)
png_warning(png_ptr, "PNG fixed point integer out of range");
return PNG_FIXED_ERROR;
}
#endif
#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
/* NOTE: the read macros will obscure these definitions, so that if
* PNG_USE_READ_MACROS is set the library will not use them internally,
* but the APIs will still be available externally.
*
* The parentheses around "PNGAPI function_name" in the following three
* functions are necessary because they allow the macros to co-exist with
* these (unused but exported) functions.
*/
/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
png_uint_32 (PNGAPI
png_get_uint_32)(png_const_bytep buf)
{
png_uint_32 uval =
((png_uint_32)(*(buf )) << 24) +
((png_uint_32)(*(buf + 1)) << 16) +
((png_uint_32)(*(buf + 2)) << 8) +
((png_uint_32)(*(buf + 3)) ) ;
return uval;
}
/* Grab a signed 32-bit integer from a buffer in big-endian format. The
* data is stored in the PNG file in two's complement format and there
* is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
* the following code does a two's complement to native conversion.
*/
png_int_32 (PNGAPI
png_get_int_32)(png_const_bytep buf)
{
png_uint_32 uval = png_get_uint_32(buf);
if ((uval & 0x80000000) == 0) /* non-negative */
return uval;
uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
return -(png_int_32)uval;
}
/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
png_uint_16 (PNGAPI
png_get_uint_16)(png_const_bytep buf)
{
/* ANSI-C requires an int value to accomodate at least 16 bits so this
* works and allows the compiler not to worry about possible narrowing
* on 32 bit systems. (Pre-ANSI systems did not make integers smaller
* than 16 bits either.)
*/
unsigned int val =
((unsigned int)(*buf) << 8) +
((unsigned int)(*(buf + 1)));
return (png_uint_16)val;
}
#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */
/* Read and check the PNG file signature */
void /* PRIVATE */
png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
{
png_size_t num_checked, num_to_check;
/* Exit if the user application does not expect a signature. */
if (png_ptr->sig_bytes >= 8)
return;
num_checked = png_ptr->sig_bytes;
num_to_check = 8 - num_checked;
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;
#endif
/* The signature must be serialized in a single I/O call. */
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 (num_checked < 4 &&
png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
png_error(png_ptr, "Not a PNG file");
else
png_error(png_ptr, "PNG file corrupted by ASCII conversion");
}
if (num_checked < 3)
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
}
/* Read the chunk header (length + type name).
* Put the type name into png_ptr->chunk_name, and return the length.
*/
png_uint_32 /* PRIVATE */
png_read_chunk_header(png_structrp png_ptr)
{
png_byte buf[8];
png_uint_32 length;
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
#endif
/* Read the length and the chunk name.
* This must be performed in a single I/O call.
*/
png_read_data(png_ptr, buf, 8);
length = png_get_uint_31(png_ptr, buf);
/* Put the chunk name into png_ptr->chunk_name. */
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
png_debug2(0, "Reading %lx chunk, length = %lu",
(unsigned long)png_ptr->chunk_name, (unsigned long)length);
/* Reset the crc and run it over the chunk name. */
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, buf + 4, 4);
/* Check to see if chunk name is valid. */
png_check_chunk_name(png_ptr, png_ptr->chunk_name);
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
#endif
return length;
}
/* Read data, and (optionally) run it through the CRC. */
void /* PRIVATE */
png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length)
{
if (png_ptr == NULL)
return;
png_read_data(png_ptr, buf, length);
png_calculate_crc(png_ptr, buf, length);
}
/* Optionally skip data and then check the CRC. Depending on whether we
* are reading a ancillary or critical chunk, and how the program has set
* things up, we may calculate the CRC on the data and print a message.
* Returns '1' if there was a CRC error, '0' otherwise.
*/
int /* PRIVATE */
png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
{
/* 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_uint_32 len;
png_byte tmpbuf[PNG_INFLATE_BUF_SIZE];
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_CHUNK_ANCILLIARY(png_ptr->chunk_name) ?
!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) :
(png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
{
png_chunk_warning(png_ptr, "CRC error");
}
else
{
png_chunk_benign_error(png_ptr, "CRC error");
return (0);
}
return (1);
}
return (0);
}
/* Compare the CRC stored in the PNG file with that calculated by libpng from
* the data it has read thus far.
*/
int /* PRIVATE */
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_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
need_crc = 0;
}
else /* critical */
{
if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
need_crc = 0;
}
#ifdef PNG_IO_STATE_SUPPORTED
png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
#endif
/* The chunk CRC must be serialized in a single I/O call. */
png_read_data(png_ptr, crc_bytes, 4);
if (need_crc)
{
crc = png_get_uint_32(crc_bytes);
return ((int)(crc != png_ptr->crc));
}
else
return (0);
}
/* 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_bytep buffer = png_ptr->read_buffer;
if (buffer != NULL && new_size > png_ptr->read_buffer_size)
{
png_ptr->read_buffer = NULL;
png_ptr->read_buffer = NULL;
png_ptr->read_buffer_size = 0;
png_free(png_ptr, buffer);
buffer = NULL;
}
if (buffer == NULL)
{
buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size));
if (buffer != NULL)
{
png_ptr->read_buffer = buffer;
png_ptr->read_buffer_size = new_size;
}
else if (warn < 2) /* else silent */
{
#ifdef PNG_WARNINGS_SUPPORTED
if (warn)
png_chunk_warning(png_ptr, "insufficient memory to read chunk");
else
#endif
{
#ifdef PNG_ERROR_TEXT_SUPPORTED
png_chunk_error(png_ptr, "insufficient memory to read chunk");
#endif
}
}
}
return buffer;
}
/* 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, int window_bits)
{
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.
*/
(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
}
/* 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 a chimera: 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 applications 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 */
/* Set this for safety, just in case the previous owner left pointers to
* memory allocations.
*/
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 (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
{
# if ZLIB_VERNUM < 0x1240
PNG_UNUSED(window_bits)
ret = inflateReset(&png_ptr->zstream);
# else
ret = inflateReset2(&png_ptr->zstream, window_bits);
# endif
}
else
{
# if ZLIB_VERNUM < 0x1240
ret = inflateInit(&png_ptr->zstream);
# else
ret = inflateInit2(&png_ptr->zstream, window_bits);
# endif
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
if (ret == Z_OK)
png_ptr->zowner = owner;
else
png_zstream_error(png_ptr, ret);
return ret;
}
}
#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;
png_ptr->zstream.avail_out = 0;
/* Read directly into the output if it is available (this is set to
* a local buffer below if output is NULL).
*/
if (output != NULL)
png_ptr->zstream.next_out = output;
do
{
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 */
avail = ZLIB_IO_MAX;
if (avail_in < avail)
avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */
avail_in -= avail;
png_ptr->zstream.avail_in = avail;
/* zlib OUTPUT BUFFER */
avail_out += png_ptr->zstream.avail_out; /* not written last time */
avail = ZLIB_IO_MAX; /* maximum zlib can process */
if (output == NULL)
{
/* 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);
}
if (avail_out < avail)
avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */
png_ptr->zstream.avail_out = avail;
avail_out -= avail;
/* zlib inflate call */
/* In fact 'avail_out' may be 0 at this point, that happens at the end
* of the read when the final LZ end code was not passed at the end of
* the previous chunk of input data. Tell zlib if we have reached the
* end of the output buffer.
*/
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.
*/
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 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).
*/
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*/)
{
/* 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;
# 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))
{
int ret;
limit -= prefix_size + (terminate != 0);
if (limit < *newlength)
*newlength = limit;
/* Now try to claim the stream; the 'warn' setting causes zlib to be told
* to use the maximum window size during inflate; this hides errors in the
* deflate header window bits value which is used if '0' is passed. In
* fact this only has an effect with zlib versions 1.2.4 and later - see
* the comments in png_inflate_claim above.
*/
ret = png_inflate_claim(png_ptr, png_ptr->chunk_name,
png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0);
if (ret == Z_OK)
{
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 (ret == Z_STREAM_END)
{
/* 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)
{
/* 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)
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);
/* 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);
}
}
else
{
/* inflateReset failed, store the error message */
png_zstream_error(png_ptr, ret);
if (ret == Z_STREAM_END)
ret = PNG_UNEXPECTED_ZLIB_RETURN;
}
}
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
{
/* Application/configuration limits exceeded */
png_zstream_error(png_ptr, Z_MEM_ERROR);
return Z_MEM_ERROR;
}
}
#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
#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)
{
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 */
do
{
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_ptr->zstream.avail_out = avail;
}
/* 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));
}
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;
}
else
{
png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed");
return Z_STREAM_ERROR;
}
}
#endif
/* Read and check the IDHR chunk */
void /* PRIVATE */
png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[13];
png_uint_32 width, height;
int bit_depth, color_type, compression_type, filter_type;
int interlace_type;
png_debug(1, "in png_handle_IHDR");
if (png_ptr->mode & PNG_HAVE_IHDR)
png_chunk_error(png_ptr, "out of place");
/* Check the length */
if (length != 13)
png_chunk_error(png_ptr, "invalid");
png_ptr->mode |= PNG_HAVE_IHDR;
png_crc_read(png_ptr, buf, 13);
png_crc_finish(png_ptr, 0);
width = png_get_uint_31(png_ptr, buf);
height = png_get_uint_31(png_ptr, buf + 4);
bit_depth = buf[8];
color_type = buf[9];
compression_type = buf[10];
filter_type = buf[11];
interlace_type = buf[12];
/* Set internal variables */
png_ptr->width = width;
png_ptr->height = height;
png_ptr->bit_depth = (png_byte)bit_depth;
png_ptr->interlaced = (png_byte)interlace_type;
png_ptr->color_type = (png_byte)color_type;
#ifdef PNG_MNG_FEATURES_SUPPORTED
png_ptr->filter_type = (png_byte)filter_type;
#endif
png_ptr->compression_type = (png_byte)compression_type;
/* Find number of channels */
switch (png_ptr->color_type)
{
default: /* invalid, png_set_IHDR calls png_error */
case PNG_COLOR_TYPE_GRAY:
case PNG_COLOR_TYPE_PALETTE:
png_ptr->channels = 1;
break;
case PNG_COLOR_TYPE_RGB:
png_ptr->channels = 3;
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
png_ptr->channels = 2;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
png_ptr->channels = 4;
break;
}
/* Set up other useful info */
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);
png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
color_type, interlace_type, compression_type, filter_type);
}
/* Read and check the palette */
void /* PRIVATE */
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;
#ifdef PNG_POINTER_INDEXING_SUPPORTED
png_colorp pal_ptr;
#endif
png_debug(1, "in png_handle_PLTE");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
/* 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)
png_chunk_error(png_ptr, "duplicate");
else if (png_ptr->mode & PNG_HAVE_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;
}
png_ptr->mode |= PNG_HAVE_PLTE;
if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "ignored in grayscale PNG");
return;
}
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
{
png_crc_finish(png_ptr, length);
return;
}
#endif
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_chunk_benign_error(png_ptr, "invalid");
else
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
for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
{
png_byte buf[3];
png_crc_read(png_ptr, buf, 3);
pal_ptr->red = buf[0];
pal_ptr->green = buf[1];
pal_ptr->blue = buf[2];
}
#else
for (i = 0; i < num; i++)
{
png_byte buf[3];
png_crc_read(png_ptr, buf, 3);
/* Don't depend upon png_color being any order */
palette[i].red = buf[0];
palette[i].green = buf[1];
palette[i].blue = buf[2];
}
#endif
/* If we actually need the PLTE chunk (ie for a paletted image), we do
* whatever the normal CRC configuration tells us. However, if we
* have an RGB image, the PLTE can be considered ancillary, so
* we will act as though it is.
*/
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
#endif
{
png_crc_finish(png_ptr, 0);
}
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
{
/* If we don't want to use the data from an ancillary chunk,
* 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_NOWARN)
{
png_chunk_benign_error(png_ptr, "CRC error");
}
else
{
png_chunk_warning(png_ptr, "CRC error");
return;
}
}
/* Otherwise, we (optionally) emit a warning and use the chunk. */
else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
{
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->num_trans > 0 ||
(info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0))
{
/* 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 != 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_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_chunk_error(png_ptr, "out of place");
png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
png_crc_finish(png_ptr, length);
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_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_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 4)
{
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))
return;
igamma = png_get_fixed_point(NULL, buf);
/* The gAMA value is unsigned (and is a power law correction, so 0 is
* meaningless.)
*/
if (igamma <= 0)
{
png_chunk_benign_error(png_ptr, "out of range");
return;
}
/* If a colorspace error has already been output skip this chunk */
if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
return;
if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA)
{
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
png_colorspace_sync(png_ptr, info_ptr);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA;
(void)png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma,
1/*prefer gAMA values*/);
png_colorspace_sync(png_ptr, info_ptr);
}
#endif
#ifdef PNG_READ_sBIT_SUPPORTED
void /* PRIVATE */
png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
unsigned int truelen;
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_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
{
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;
else
truelen = png_ptr->channels;
if (length != truelen || length > 4)
{
png_chunk_benign_error(png_ptr, "invalid");
png_crc_finish(png_ptr, length);
return;
}
png_crc_read(png_ptr, buf, truelen);
if (png_crc_finish(png_ptr, 0))
return;
if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
{
png_ptr->sig_bit.red = buf[0];
png_ptr->sig_bit.green = buf[1];
png_ptr->sig_bit.blue = buf[2];
png_ptr->sig_bit.alpha = buf[3];
}
else
{
png_ptr->sig_bit.gray = buf[0];
png_ptr->sig_bit.red = buf[0];
png_ptr->sig_bit.green = buf[0];
png_ptr->sig_bit.blue = buf[0];
png_ptr->sig_bit.alpha = buf[1];
}
png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
}
#endif
#ifdef PNG_READ_cHRM_SUPPORTED
void /* PRIVATE */
png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte buf[32];
png_xy xy;
png_debug(1, "in png_handle_cHRM");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 32)
{
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))
return;
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;
}
/* If a colorspace error has already been output skip this chunk */
if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
return;
if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM)
{
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
png_colorspace_sync(png_ptr, info_ptr);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
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_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_byte intent;
png_debug(1, "in png_handle_sRGB");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
if (length != 1)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, &intent, 1);
if (png_crc_finish(png_ptr, 0))
return;
/* Check for bad intent */
if (intent >= PNG_sRGB_INTENT_LAST)
{
png_chunk_benign_error(png_ptr, "Unknown sRGB intent");
return;
}
/* If a colorspace error has already been output skip this chunk */
if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
return;
/* 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)
{
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
png_colorspace_sync(png_ptr, info_ptr);
png_chunk_benign_error(png_ptr, "too many profiles");
return;
}
/* Do not override gAMA or cHRM from the PNG file; just check they match.
* This is because we write a cHRM which corresponds to D65, however there is
* an issue with CMMs that assume a D50 environment that requires adaptation
* of the white point. This way at least it is possible to supply an
* adapated value (so long as it is within the tolerance limits for a match
* against the D65 chromaticities.)
*
* TODO: get expert opinions on this issue
*/
(void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent, 0);
png_colorspace_sync(png_ptr, info_ptr);
}
#endif /* PNG_READ_sRGB_SUPPORTED */
#ifdef PNG_READ_iCCP_SUPPORTED
void /* PRIVATE */
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_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_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
/* 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 one character and there is a
* terminator (0) byte and the compression method.
*/
if (length < 9)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "too short");
return;
}
/* If a colorspace error has already been output skip this chunk */
if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID)
{
png_crc_finish(png_ptr, length);
return;
}
/* 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)
{
uInt read_length, keyword_length;
char keyword[81];
/* 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;
png_crc_read(png_ptr, (png_bytep)keyword, read_length);
length -= read_length;
keyword_length = 0;
while (keyword_length < 80 && keyword_length < read_length &&
keyword[keyword_length] != 0)
++keyword_length;
/* 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;
if (png_inflate_claim(png_ptr, png_iCCP,
png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK)
{
Byte profile_header[132];
Byte local_buffer[PNG_INFLATE_BUF_SIZE];
png_alloc_size_t size = (sizeof profile_header);
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*/);
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);
if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
keyword, profile_length))
{
/* 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))
{
/* 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 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))
{
/* 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)
{
int ok;
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;
/* Set the gAMA and cHRM information, this
* checks for a known sRGB profile. The
* result is 0 on error.
*/
ok = png_icc_set_gAMA_and_cHRM(png_ptr,
&png_ptr->colorspace, keyword, profile,
png_ptr->zstream.adler,
0/*prefer explicit gAMA/cHRM*/);
/* Steal the profile for info_ptr. */
if (ok && 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 && ok)
{
png_ptr->zowner = 0;
return;
}
/* else png_icc_set_gAMA_and_cHRM has
* already output an error.
*/
}
else if (size > 0)
errmsg = "truncated";
else
errmsg = png_ptr->zstream.msg;
}
/* else png_icc_check_tag_table output an error */
}
else /* profile truncated */
errmsg = png_ptr->zstream.msg;
}
else
errmsg = "out of memory";
}
/* else png_icc_check_header output an error */
}
/* else png_icc_check_length output an error */
}
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";
}
else
errmsg = "too many profiles";
/* Failure: the reason is in 'errmsg' */
if (!finished)
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 */
#ifdef PNG_READ_sPLT_SUPPORTED
void /* PRIVATE */
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, 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_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)
{
png_crc_finish(png_ptr, length);
return;
}
if (--png_ptr->user_chunk_cache_max == 1)
{
png_warning(png_ptr, "No space in chunk cache for sPLT");
png_crc_finish(png_ptr, length);
return;
}
}
#endif
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_IDAT)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of place");
return;
}
#ifdef PNG_MAX_MALLOC_64K
if (length > 65535U)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "too large to fit in memory");
return;
}
#endif
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.
*/
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, skip))
return;
buffer[length] = 0;
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 > buffer + length - 2)
{
png_warning(png_ptr, "malformed sPLT chunk");
return;
}
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.
*/
data_length = length - (png_uint_32)(entry_start - buffer);
/* Integrity-check the data length */
if (data_length % entry_size)
{
png_warning(png_ptr, "sPLT chunk has bad length");
return;
}
dl = (png_int_32)(data_length / entry_size);
max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry));
if (dl > max_dl)
{
png_warning(png_ptr, "sPLT chunk too long");
return;
}
new_palette.nentries = (png_int_32)(data_length / entry_size);
new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry)));
if (new_palette.entries == NULL)
{
png_warning(png_ptr, "sPLT chunk requires too much memory");
return;
}
#ifdef PNG_POINTER_INDEXING_SUPPORTED
for (i = 0; i < new_palette.nentries; i++)
{
pp = new_palette.entries + i;
if (new_palette.depth == 8)
{
pp->red = *entry_start++;
pp->green = *entry_start++;
pp->blue = *entry_start++;
pp->alpha = *entry_start++;
}
else
{
pp->red = png_get_uint_16(entry_start); entry_start += 2;
pp->green = png_get_uint_16(entry_start); entry_start += 2;
pp->blue = png_get_uint_16(entry_start); entry_start += 2;
pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
}
pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
}
#else
pp = new_palette.entries;
for (i = 0; i < new_palette.nentries; i++)
{
if (new_palette.depth == 8)
{
pp[i].red = *entry_start++;
pp[i].green = *entry_start++;
pp[i].blue = *entry_start++;
pp[i].alpha = *entry_start++;
}
else
{
pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
}
pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;
}
#endif
/* Discard all chunk data except the name and stash that */
new_palette.name = (png_charp)buffer;
png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
png_free(png_ptr, new_palette.entries);
}
#endif /* PNG_READ_sPLT_SUPPORTED */
#ifdef PNG_READ_tRNS_SUPPORTED
void /* PRIVATE */
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_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_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))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
png_byte buf[2];
if (length != 2)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, buf, 2);
png_ptr->num_trans = 1;
png_ptr->trans_color.gray = png_get_uint_16(buf);
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
png_byte buf[6];
if (length != 6)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
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);
png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (!(png_ptr->mode & PNG_HAVE_PLTE))
{
/* 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 > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH ||
length == 0)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
png_crc_read(png_ptr, readbuf, length);
png_ptr->num_trans = (png_uint_16)length;
}
else
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid with alpha channel");
return;
}
if (png_crc_finish(png_ptr, 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));
}
#endif
#ifdef PNG_READ_bKGD_SUPPORTED
void /* PRIVATE */
png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
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_chunk_error(png_ptr, "missing IHDR");
else if ((png_ptr->mode & PNG_HAVE_IDAT) ||
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
!(png_ptr->mode & PNG_HAVE_PLTE)))
{
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_bKGD))
{
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)
truelen = 6;
else
truelen = 2;
if (length != truelen)
{
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))
return;
/* We convert the index value into RGB components so that we can allow
* arbitrary RGB values for background when we have transparency, and
* so it is easy to determine the RGB values of the background color
* from the info_ptr struct.
*/
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
background.index = buf[0];
if (info_ptr && info_ptr->num_palette)
{
if (buf[0] >= info_ptr->num_palette)
{
png_chunk_benign_error(png_ptr, "invalid index");
return;
}
background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
}
else
background.red = background.green = background.blue = 0;
background.gray = 0;
}
else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
{
background.index = 0;
background.red =
background.green =
background.blue =
background.gray = png_get_uint_16(buf);
}
else
{
background.index = 0;
background.red = png_get_uint_16(buf);
background.green = png_get_uint_16(buf + 2);
background.blue = png_get_uint_16(buf + 4);
background.gray = 0;
}
png_set_bKGD(png_ptr, info_ptr, &background);
}
#endif
#ifdef PNG_READ_hIST_SUPPORTED
void /* PRIVATE */
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_chunk_error(png_ptr, "missing IHDR");
else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE))
{
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_hIST))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
num = length / 2 ;
if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "invalid");
return;
}
for (i = 0; i < num; i++)
{
png_byte buf[2];
png_crc_read(png_ptr, buf, 2);
readbuf[i] = png_get_uint_16(buf);
}
if (png_crc_finish(png_ptr, 0))
return;
png_set_hIST(png_ptr, info_ptr, readbuf);
}
#endif
#ifdef PNG_READ_pHYs_SUPPORTED
void /* PRIVATE */
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;
int unit_type;
png_debug(1, "in png_handle_pHYs");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_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))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
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))
return;
res_x = png_get_uint_32(buf);
res_y = png_get_uint_32(buf + 4);
unit_type = buf[8];
png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
}
#endif
#ifdef PNG_READ_oFFs_SUPPORTED
void /* PRIVATE */
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;
int unit_type;
png_debug(1, "in png_handle_oFFs");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_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))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (length != 9)
{
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))
return;
offset_x = png_get_int_32(buf);
offset_y = png_get_int_32(buf + 4);
unit_type = buf[8];
png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
}
#endif
#ifdef PNG_READ_pCAL_SUPPORTED
/* Read the pCAL chunk (described in the PNG Extensions document) */
void /* PRIVATE */
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_bytep buffer, buf, units, endptr;
png_charpp params;
int i;
png_debug(1, "in png_handle_pCAL");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_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))
{
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);
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;
}
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, 0))
return;
buffer[length] = 0; /* Null terminate the last string */
png_debug(3, "Finding end of pCAL purpose string");
for (buf = buffer; *buf; buf++)
/* Empty loop */ ;
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_chunk_benign_error(png_ptr, "invalid");
return;
}
png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
X0 = png_get_int_32((png_bytep)buf+1);
X1 = png_get_int_32((png_bytep)buf+5);
type = buf[9];
nparams = buf[10];
units = buf + 11;
png_debug(3, "Checking pCAL equation type and number of parameters");
/* Check that we have the right number of parameters for known
* equation types.
*/
if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
(type == PNG_EQUATION_BASE_E && nparams != 3) ||
(type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
(type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
{
png_chunk_benign_error(png_ptr, "invalid parameter count");
return;
}
else if (type >= PNG_EQUATION_LAST)
{
png_chunk_benign_error(png_ptr, "unrecognized equation type");
}
for (buf = units; *buf; buf++)
/* Empty loop to move past the units string. */ ;
png_debug(3, "Allocating pCAL parameters array");
params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
nparams * (sizeof (png_charp))));
if (params == NULL)
{
png_chunk_benign_error(png_ptr, "out of memory");
return;
}
/* Get pointers to the start of each parameter string. */
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] = (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_free(png_ptr, params);
png_chunk_benign_error(png_ptr, "invalid data");
return;
}
}
png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams,
(png_charp)units, params);
png_free(png_ptr, params);
}
#endif
#ifdef PNG_READ_sCAL_SUPPORTED
/* Read the sCAL chunk */
void /* PRIVATE */
png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_bytep buffer;
png_size_t i;
int state;
png_debug(1, "in png_handle_sCAL");
if (!(png_ptr->mode & PNG_HAVE_IHDR))
png_chunk_error(png_ptr, "missing IHDR");
else if (png_ptr->mode & PNG_HAVE_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))
{
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_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);
buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/);
if (buffer == NULL)
{
png_chunk_benign_error(png_ptr, "out of memory");
png_crc_finish(png_ptr, length);
return;
}
png_crc_read(png_ptr, buffer, length);
buffer[length] = 0; /* Null terminate the last string */
if (png_crc_finish(png_ptr, 0))
return;
/* Validate the unit. */
if (buffer[0] != 1 && buffer[0] != 2)
{
png_chunk_benign_error(png_ptr, "invalid unit");
return;
}
/* Validate the ASCII numbers, need two ASCII numbers separated by
* a '\0' and they need to fit exactly in the chunk data.
*/
i = 1;
state = 0;
if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) ||
i >= length || buffer[i++] != 0)
png_chunk_benign_error(png_ptr, "bad width format");
else if (!PNG_FP_IS_POSITIVE(state))
png_chunk_benign_error(png_ptr, "non-positive width");
else
{
png_size_t heighti = i;
state = 0;
if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) ||
i != length)
png_chunk_benign_error(png_ptr, "bad height format");
else if (!PNG_FP_IS_POSITIVE(state))
png_chunk_benign_error(png_ptr, "non-positive height");
else
/* This is the (only) success case. */
png_set_sCAL_s(png_ptr, info_ptr, buffer[0],
(png_charp)buffer+1, (png_charp)buffer+heighti);
}
}
#endif
#ifdef PNG_READ_tIME_SUPPORTED
void /* PRIVATE */
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_chunk_error(png_ptr, "missing IHDR");
else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "duplicate");
return;
}
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
if (length != 7)
{
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))
return;
mod_time.second = buf[6];
mod_time.minute = buf[5];
mod_time.hour = buf[4];
mod_time.day = buf[3];
mod_time.month = buf[2];
mod_time.year = png_get_uint_16(buf);
png_set_tIME(png_ptr, info_ptr, &mod_time);
}
#endif
#ifdef PNG_READ_tEXt_SUPPORTED
/* Note: this does not properly handle chunks that are > 64K under DOS */
void /* PRIVATE */
png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_text text_info;
png_bytep buffer;
png_charp key;
png_charp text;
png_uint_32 skip = 0;
png_debug(1, "in png_handle_tEXt");
#ifdef PNG_USER_LIMITS_SUPPORTED
if (png_ptr->user_chunk_cache_max != 0)
{
if (png_ptr->user_chunk_cache_max == 1)
{
png_crc_finish(png_ptr, length);
return;
}
if (--png_ptr->user_chunk_cache_max == 1)
{
png_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_chunk_error(png_ptr, "missing IHDR");
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
#ifdef PNG_MAX_MALLOC_64K
if (length > 65535U)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "too large to fit in memory");
return;
}
#endif
buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
if (buffer == NULL)
{
png_chunk_benign_error(png_ptr, "out of memory");
return;
}
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, skip))
return;
key = (png_charp)buffer;
key[length] = 0;
for (text = key; *text; text++)
/* Empty loop to find end of key */ ;
if (text != key + length)
text++;
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 (png_set_text_2(png_ptr, info_ptr, &text_info, 1))
png_warning(png_ptr, "Insufficient memory to process text chunk");
}
#endif
#ifdef PNG_READ_zTXt_SUPPORTED
/* Note: this does not correctly handle chunks that are > 64K under DOS */
void /* PRIVATE */
png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_const_charp errmsg = NULL;
png_bytep buffer;
png_uint_32 keyword_length;
png_debug(1, "in png_handle_zTXt");
#ifdef PNG_USER_LIMITS_SUPPORTED
if (png_ptr->user_chunk_cache_max != 0)
{
if (png_ptr->user_chunk_cache_max == 1)
{
png_crc_finish(png_ptr, length);
return;
}
if (--png_ptr->user_chunk_cache_max == 1)
{
png_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_chunk_error(png_ptr, "missing IHDR");
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
buffer = png_read_buffer(png_ptr, length, 2/*silent*/);
if (buffer == NULL)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of memory");
return;
}
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, 0))
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 */ ;
if (keyword_length > 79 || keyword_length < 1)
errmsg = "bad keyword";
/* zTXt must have some LZ data after the keyword, although it may expand to
* zero bytes; we need a '\0' at the end of the keyword, the compression type
* then the LZ data:
*/
else if (keyword_length + 3 > length)
errmsg = "truncated";
else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE)
errmsg = "unknown compression type";
else
{
png_alloc_size_t uncompressed_length = PNG_SIZE_MAX;
/* TODO: at present png_decompress_chunk imposes a single application
* level memory limit, this should be split to different values for iCCP
* and text chunks.
*/
if (png_decompress_chunk(png_ptr, length, keyword_length+2,
&uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
{
png_text 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))
errmsg = "insufficient memory";
}
else
errmsg = png_ptr->zstream.msg;
}
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_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
{
png_const_charp errmsg = NULL;
png_bytep buffer;
png_uint_32 prefix_length;
png_debug(1, "in png_handle_iTXt");
#ifdef PNG_USER_LIMITS_SUPPORTED
if (png_ptr->user_chunk_cache_max != 0)
{
if (png_ptr->user_chunk_cache_max == 1)
{
png_crc_finish(png_ptr, length);
return;
}
if (--png_ptr->user_chunk_cache_max == 1)
{
png_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_chunk_error(png_ptr, "missing IHDR");
if (png_ptr->mode & PNG_HAVE_IDAT)
png_ptr->mode |= PNG_AFTER_IDAT;
buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/);
if (buffer == NULL)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "out of memory");
return;
}
png_crc_read(png_ptr, buffer, length);
if (png_crc_finish(png_ptr, 0))
return;
/* First the keyword. */
for (prefix_length=0;
prefix_length < length && buffer[prefix_length] != 0;
++prefix_length)
/* Empty loop */ ;
/* Perform a basic check on the keyword length here. */
if (prefix_length > 79 || prefix_length < 1)
errmsg = "bad 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";
else if (buffer[prefix_length+1] == 0 ||
(buffer[prefix_length+1] == 1 &&
buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE))
{
int compressed = buffer[prefix_length+1] != 0;
png_uint_32 language_offset, translated_keyword_offset;
png_alloc_size_t uncompressed_length = 0;
/* Now the language tag */
prefix_length += 3;
language_offset = prefix_length;
for (; prefix_length < length && buffer[prefix_length] != 0;
++prefix_length)
/* Empty loop */ ;
/* WARNING: the length may be invalid here, this is checked below. */
translated_keyword_offset = ++prefix_length;
for (; prefix_length < length && buffer[prefix_length] != 0;
++prefix_length)
/* Empty loop */ ;
/* prefix_length should now be at the trailing '\0' of the translated
* keyword, but it may already be over the end. None of this arithmetic
* can overflow because chunks are at most 2^31 bytes long, but on 16-bit
* systems the available allocaton may overflow.
*/
++prefix_length;
if (!compressed && prefix_length <= length)
uncompressed_length = length - prefix_length;
else if (compressed && prefix_length < length)
{
uncompressed_length = PNG_SIZE_MAX;
/* TODO: at present png_decompress_chunk imposes a single application
* level memory limit, this should be split to different values for
* iCCP and text chunks.
*/
if (png_decompress_chunk(png_ptr, length, prefix_length,
&uncompressed_length, 1/*terminate*/) == Z_STREAM_END)
buffer = png_ptr->read_buffer;
else
errmsg = png_ptr->zstream.msg;
}
else
errmsg = "truncated";
if (errmsg == NULL)
{
png_text text;
buffer[uncompressed_length+prefix_length] = 0;
if (compressed)
text.compression = PNG_ITXT_COMPRESSION_NONE;
else
text.compression = PNG_ITXT_COMPRESSION_zTXt;
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;
if (png_set_text_2(png_ptr, info_ptr, &text, 1))
errmsg = "insufficient memory";
}
}
else
errmsg = "bad compression info";
if (errmsg != NULL)
png_chunk_benign_error(png_ptr, errmsg);
}
#endif
#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_alloc_size_t limit = PNG_SIZE_MAX;
if (png_ptr->unknown_chunk.data != NULL)
{
png_free(png_ptr, png_ptr->unknown_chunk.data);
png_ptr->unknown_chunk.data = NULL;
}
# 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)
{
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 (length == 0)
png_ptr->unknown_chunk.data = NULL;
else
{
/* Do a 'warn' here - it is handled below. */
png_ptr->unknown_chunk.data = png_voidcast(png_bytep,
png_malloc_warn(png_ptr, length));
}
}
if (png_ptr->unknown_chunk.data == NULL && length > 0)
{
/* 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;
}
else
{
if (length > 0)
png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);
png_crc_finish(png_ptr, 0);
return 1;
}
}
#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */
/* 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
/* 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
/* 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.
*/
if (png_ptr->read_user_chunk_fn != NULL)
{
if (png_cache_unknown_chunk(png_ptr, length))
{
/* 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 occured, 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");
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 neither set specific save for this chunk
* or global save.
*/
if (keep < PNG_HANDLE_CHUNK_IF_SAFE)
{
# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE)
png_app_warning(png_ptr,
"forcing save of an unhandled chunk; please call png_set_keep_unknown_chunks");
# 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 */
}
# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
else
# endif
# endif /* PNG_READ_USER_CHUNKS_SUPPORTED */
# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
{
/* 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_ANCILLIARY(png_ptr->chunk_name)))
{
if (!png_cache_unknown_chunk(png_ptr, length))
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
# endif
# 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_ANCILLIARY(png_ptr->chunk_name)))
{
# ifdef PNG_USER_LIMITS_SUPPORTED
switch (png_ptr->user_chunk_cache_max)
{
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;
default: /* not at limit */
--(png_ptr->user_chunk_cache_max);
/* FALL THROUGH */
case 0: /* no limit */
# endif /* PNG_USER_LIMITS_SUPPORTED */
/* 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! */
PNG_UNUSED(info_ptr)
# error untested code (reading unknown chunks with no store support)
# endif
/* 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 /* !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 /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */
/* Check for unhandled critical chunks */
if (!handled && 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.
* This function can't have the "critical chunk check" incorporated
* into it, since in the future we will need to be able to call user
* functions to handle unknown critical chunks after we check that
* the chunk name itself is valid.
*/
/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:
*
* ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
*/
void /* PRIVATE */
png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name)
{
int i;
png_debug(1, "in png_check_chunk_name");
for (i=1; i<=4; ++i)
{
int c = chunk_name & 0xff;
if (c < 65 || c > 122 || (c > 90 && c < 97))
png_chunk_error(png_ptr, "invalid chunk type");
chunk_name >>= 8;
}
}
/* Combines the row recently read in with the existing pixels in the row. This
* routine takes care of alpha and transparency if requested. This routine also
* handles the two methods of progressive display of interlaced images,
* depending on the 'display' value; if 'display' is true then the whole row
* (dp) is filled from the start by replicating the available pixels. If
* 'display' is false only those pixels present in the pass are filled in.
*/
void /* PRIVATE */
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;
unsigned int pass = png_ptr->pass;
png_bytep end_ptr = 0;
png_byte end_byte = 0;
unsigned int end_mask;
png_debug(1, "in png_combine_row");
/* Added in 1.5.6: it should not be possible to enter this routine until at
* least one row has been read from the PNG data and transformed.
*/
if (pixel_depth == 0)
png_error(png_ptr, "internal row logic error");
/* Added in 1.5.4: the pixel depth should match the information returned by
* any call to png_read_update_info at this point. Do not continue if we got
* this wrong.
*/
if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=
PNG_ROWBYTES(pixel_depth, row_width))
png_error(png_ptr, "internal row size calculation error");
/* Don't expect this to ever happen: */
if (row_width == 0)
png_error(png_ptr, "internal row width error");
/* Preserve the last byte in cases where only part of it will be overwritten,
* the multiply below may overflow, we don't care because ANSI-C guarantees
* we get the low bits.
*/
end_mask = (pixel_depth * row_width) & 7;
if (end_mask != 0)
{
/* end_ptr == NULL is a flag to say do nothing */
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 */
end_mask = 0xff << end_mask;
else /* big-endian byte */
# endif
end_mask = 0xff >> end_mask;
/* end_mask is now the bits to *keep* from the destination row */
}
/* 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)))
{
/* Narrow images may have no bits in a pass; the caller should handle
* this, but this test is cheap:
*/
if (row_width <= PNG_PASS_START_COL(pass))
return;
if (pixel_depth < 8)
{
/* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit
* into 32 bits, then a single loop over the bytes using the four byte
* values in the 32-bit mask can be used. For the 'display' option the
* expanded mask may also not require any masking within a byte. To
* make this work the PACKSWAP option must be taken into account - it
* simply requires the pixels to be reversed in each byte.
*
* The 'regular' case requires a mask for each of the first 6 passes,
* the 'display' case does a copy for the even passes in the range
* 0..6. This has already been handled in the test above.
*
* The masks are arranged as four bytes with the first byte to use in
* the lowest bits (little-endian) regardless of the order (PACKSWAP or
* not) of the pixels in each byte.
*
* NOTE: the whole of this logic depends on the caller of this function
* only calling it on rows appropriate to the pass. This function only
* understands the 'x' logic; the 'y' logic is handled by the caller.
*
* The following defines allow generation of compile time constant bit
* masks for each pixel depth and each possibility of swapped or not
* swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index,
* is in the range 0..7; and the result is 1 if the pixel is to be
* copied in the pass, 0 if not. 'S' is for the sparkle method, 'B'
* for the block method.
*
* With some compilers a compile time expression of the general form:
*
* (shift >= 32) ? (a >> (shift-32)) : (b >> shift)
*
* Produces warnings with values of 'shift' in the range 33 to 63
* because the right hand side of the ?: expression is evaluated by
* the compiler even though it isn't used. Microsoft Visual C (various
* versions) and the Intel C compiler are known to do this. To avoid
* this the following macros are used in 1.5.6. This is a temporary
* solution to avoid destabilizing the code during the release process.
*/
# if PNG_USE_COMPILE_TIME_MASKS
# define PNG_LSR(x,s) ((x)>>((s) & 0x1f))
# define PNG_LSL(x,s) ((x)<<((s) & 0x1f))
# else
# define PNG_LSR(x,s) ((x)>>(s))
# define PNG_LSL(x,s) ((x)<<(s))
# endif
# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\
PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1)
# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\
PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1)
/* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is
* little endian - the first pixel is at bit 0 - however the extra
* parameter 's' can be set to cause the mask position to be swapped
* within each byte, to match the PNG format. This is done by XOR of
* the shift with 7, 6 or 4 for bit depths 1, 2 and 4.
*/
# define PIXEL_MASK(p,x,d,s) \
(PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0))))
/* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask.
*/
# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
/* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp
* cases the result needs replicating, for the 4-bpp case the above
* generates a full 32 bits.
*/
# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1)))
# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\
S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\
S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d)
# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\
B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\
B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d)
#if PNG_USE_COMPILE_TIME_MASKS
/* Utility macros to construct all the masks for a depth/swap
* combination. The 's' parameter says whether the format is PNG
* (big endian bytes) or not. Only the three odd-numbered passes are
* required for the display/block algorithm.
*/
# 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 DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
/* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and
* then pass:
*/
static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] =
{
/* Little-endian byte masks for PACKSWAP */
{ S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) },
/* Normal (big-endian byte) masks - PNG format */
{ S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) }
};
/* display_mask has only three entries for the odd passes, so index by
* pass>>1.
*/
static PNG_CONST png_uint_32 display_mask[2][3][3] =
{
/* Little-endian byte masks for PACKSWAP */
{ B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) },
/* Normal (big-endian byte) masks - PNG format */
{ B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) }
};
# define MASK(pass,depth,display,png)\
((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\
row_mask[png][DEPTH_INDEX(depth)][pass])
#else /* !PNG_USE_COMPILE_TIME_MASKS */
/* This is the runtime alternative: it seems unlikely that this will
* ever be either smaller or faster than the compile time approach.
*/
# define MASK(pass,depth,display,png)\
((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))
#endif /* !PNG_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 number of pixels, but the code copies bytes, so it is necessary
* to special case the end.
*/
png_uint_32 pixels_per_byte = 8 / pixel_depth;
png_uint_32 mask;
# ifdef PNG_READ_PACKSWAP_SUPPORTED
if (png_ptr->transformations & PNG_PACKSWAP)
mask = MASK(pass, pixel_depth, display, 0);
else
# endif
mask = MASK(pass, pixel_depth, display, 1);
for (;;)
{
png_uint_32 m;
/* It doesn't matter in the following if png_uint_32 has more than
* 32 bits because the high bits always match those in m<<24; it is,
* however, essential to use OR here, not +, because of this.
*/
m = mask;
mask = (m >> 8) | (m << 24); /* rotate right to good compilers */
m &= 0xff;
if (m != 0) /* something to copy */
{
if (m != 0xff)
*dp = (png_byte)((*dp & ~m) | (*sp & m));
else
*dp = *sp;
}
/* NOTE: this may overwrite the last byte with garbage if the image
* is not an exact number of bytes wide; libpng has always done
* this.
*/
if (row_width <= pixels_per_byte)
break; /* May need to restore part of the last byte */
row_width -= pixels_per_byte;
++dp;
++sp;
}
}
else /* pixel_depth >= 8 */
{
unsigned int bytes_to_copy, bytes_to_jump;
/* Validate the depth - it must be a multiple of 8 */
if (pixel_depth & 7)
png_error(png_ptr, "invalid user transform pixel depth");
pixel_depth >>= 3; /* now in bytes */
row_width *= pixel_depth;
/* Regardless of pass number the Adam 7 interlace always results in a
* fixed number of pixels to copy then to skip. There may be a
* different number of pixels to skip at the start though.
*/
{
unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth;
row_width -= offset;
dp += offset;
sp += offset;
}
/* Work out the bytes to copy. */
if (display)
{
/* When doing the 'block' algorithm the pixel in the pass gets
* replicated to adjacent pixels. This is why the even (0,2,4,6)
* passes are skipped above - the entire expanded row is copied.
*/
bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;
/* But don't allow this number to exceed the actual row width. */
if (bytes_to_copy > row_width)
bytes_to_copy = row_width;
}
else /* normal row; Adam7 only ever gives us one pixel to copy. */
bytes_to_copy = pixel_depth;
/* In Adam7 there is a constant offset between where the pixels go. */
bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;
/* And simply copy these bytes. Some optimization is possible here,
* depending on the value of 'bytes_to_copy'. Special case the low
* byte counts, which we know to be frequent.
*
* Notice that these cases all 'return' rather than 'break' - this
* avoids an unnecessary test on whether to restore the last byte
* below.
*/
switch (bytes_to_copy)
{
case 1:
for (;;)
{
*dp = *sp;
if (row_width <= bytes_to_jump)
return;
dp += bytes_to_jump;
sp += bytes_to_jump;
row_width -= bytes_to_jump;
}
case 2:
/* There is a possibility of a partial copy at the end here; this
* slows the code down somewhat.
*/
do
{
dp[0] = sp[0], dp[1] = sp[1];
if (row_width <= bytes_to_jump)
return;
sp += bytes_to_jump;
dp += bytes_to_jump;
row_width -= bytes_to_jump;
}
while (row_width > 1);
/* And there can only be one byte left at this point: */
*dp = *sp;
return;
case 3:
/* 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(;;)
{
dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2];
if (row_width <= bytes_to_jump)
return;
sp += bytes_to_jump;
dp += bytes_to_jump;
row_width -= bytes_to_jump;
}
default:
#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE
/* 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 memcpy there.
*/
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)
{
png_uint_32p dp32 = png_aligncast(png_uint_32p,dp);
png_const_uint_32p sp32 = png_aligncastconst(
png_const_uint_32p, sp);
unsigned int skip = (bytes_to_jump-bytes_to_copy) /
(sizeof (png_uint_32));
do
{
size_t c = bytes_to_copy;
do
{
*dp32++ = *sp32++;
c -= (sizeof (png_uint_32));
}
while (c > 0);
if (row_width <= bytes_to_jump)
return;
dp32 += skip;
sp32 += skip;
row_width -= bytes_to_jump;
}
while (bytes_to_copy <= row_width);
/* Get to here when the row_width truncates the final copy.
* There will be 1-3 bytes left to copy, so don't try the
* 16-bit loop below.
*/
dp = (png_bytep)dp32;
sp = (png_const_bytep)sp32;
do
*dp++ = *sp++;
while (--row_width > 0);
return;
}
/* Else do it in 16-bit quantities, but only if the size is
* not too large.
*/
else
{
png_uint_16p dp16 = png_aligncast(png_uint_16p, dp);
png_const_uint_16p sp16 = png_aligncastconst(
png_const_uint_16p, sp);
unsigned int skip = (bytes_to_jump-bytes_to_copy) /
(sizeof (png_uint_16));
do
{
size_t c = bytes_to_copy;
do
{
*dp16++ = *sp16++;
c -= (sizeof (png_uint_16));
}
while (c > 0);
if (row_width <= bytes_to_jump)
return;
dp16 += skip;
sp16 += skip;
row_width -= bytes_to_jump;
}
while (bytes_to_copy <= row_width);
/* End of row - 1 byte left, bytes_to_copy > row_width: */
dp = (png_bytep)dp16;
sp = (png_const_bytep)sp16;
do
*dp++ = *sp++;
while (--row_width > 0);
return;
}
}
#endif /* PNG_ALIGN_ code */
/* The true default - use a memcpy: */
for (;;)
{
memcpy(dp, sp, bytes_to_copy);
if (row_width <= bytes_to_jump)
return;
sp += bytes_to_jump;
dp += bytes_to_jump;
row_width -= bytes_to_jump;
if (bytes_to_copy > row_width)
bytes_to_copy = row_width;
}
}
/* NOT REACHED*/
} /* pixel_depth >= 8 */
/* Here if pixel_depth < 8 to check 'end_ptr' below. */
}
else
#endif
/* 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.)
*/
memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
/* Restore the overwritten bits from the last byte if necessary. */
if (end_ptr != NULL)
*end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask));
}
#ifdef PNG_READ_INTERLACING_SUPPORTED
void /* PRIVATE */
png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
png_uint_32 transformations /* Because these may affect the byte layout */)
{
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Offset to next interlace block */
static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
png_debug(1, "in png_do_read_interlace");
if (row != NULL && row_info != NULL)
{
png_uint_32 final_width;
final_width = row_info->width * png_pass_inc[pass];
switch (row_info->pixel_depth)
{
case 1:
{
png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
int sshift, dshift;
int s_start, s_end, s_inc;
int jstop = png_pass_inc[pass];
png_byte v;
png_uint_32 i;
int j;
#ifdef PNG_READ_PACKSWAP_SUPPORTED
if (transformations & PNG_PACKSWAP)
{
sshift = (int)((row_info->width + 7) & 0x07);
dshift = (int)((final_width + 7) & 0x07);
s_start = 7;
s_end = 0;
s_inc = -1;
}
else
#endif
{
sshift = 7 - (int)((row_info->width + 7) & 0x07);
dshift = 7 - (int)((final_width + 7) & 0x07);
s_start = 0;
s_end = 7;
s_inc = 1;
}
for (i = 0; i < row_info->width; i++)
{
v = (png_byte)((*sp >> sshift) & 0x01);
for (j = 0; j < jstop; j++)
{
unsigned int tmp = *dp & (0x7f7f >> (7 - dshift));
tmp |= v << dshift;
*dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
else
dshift += s_inc;
}
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
else
sshift += s_inc;
}
break;
}
case 2:
{
png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
int sshift, dshift;
int s_start, s_end, s_inc;
int jstop = png_pass_inc[pass];
png_uint_32 i;
#ifdef PNG_READ_PACKSWAP_SUPPORTED
if (transformations & PNG_PACKSWAP)
{
sshift = (int)(((row_info->width + 3) & 0x03) << 1);
dshift = (int)(((final_width + 3) & 0x03) << 1);
s_start = 6;
s_end = 0;
s_inc = -2;
}
else
#endif
{
sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
s_start = 0;
s_end = 6;
s_inc = 2;
}
for (i = 0; i < row_info->width; i++)
{
png_byte v;
int j;
v = (png_byte)((*sp >> sshift) & 0x03);
for (j = 0; j < jstop; j++)
{
unsigned int tmp = *dp & (0x3f3f >> (6 - dshift));
tmp |= v << dshift;
*dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
else
dshift += s_inc;
}
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
else
sshift += s_inc;
}
break;
}
case 4:
{
png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
int sshift, dshift;
int s_start, s_end, s_inc;
png_uint_32 i;
int jstop = png_pass_inc[pass];
#ifdef PNG_READ_PACKSWAP_SUPPORTED
if (transformations & PNG_PACKSWAP)
{
sshift = (int)(((row_info->width + 1) & 0x01) << 2);
dshift = (int)(((final_width + 1) & 0x01) << 2);
s_start = 4;
s_end = 0;
s_inc = -4;
}
else
#endif
{
sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
s_start = 0;
s_end = 4;
s_inc = 4;
}
for (i = 0; i < row_info->width; i++)
{
png_byte v = (png_byte)((*sp >> sshift) & 0x0f);
int j;
for (j = 0; j < jstop; j++)
{
unsigned int tmp = *dp & (0xf0f >> (4 - dshift));
tmp |= v << dshift;
*dp = (png_byte)(tmp & 0xff);
if (dshift == s_end)
{
dshift = s_start;
dp--;
}
else
dshift += s_inc;
}
if (sshift == s_end)
{
sshift = s_start;
sp--;
}
else
sshift += s_inc;
}
break;
}
default:
{
png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
png_bytep sp = row + (png_size_t)(row_info->width - 1)
* pixel_bytes;
png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
int jstop = png_pass_inc[pass];
png_uint_32 i;
for (i = 0; i < row_info->width; i++)
{
png_byte v[8];
int j;
memcpy(v, sp, pixel_bytes);
for (j = 0; j < jstop; j++)
{
memcpy(dp, v, pixel_bytes);
dp -= pixel_bytes;
}
sp -= pixel_bytes;
}
break;
}
}
row_info->width = final_width;
row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
}
#ifndef PNG_READ_PACKSWAP_SUPPORTED
PNG_UNUSED(transformations) /* Silence compiler warning */
#endif
}
#endif /* PNG_READ_INTERLACING_SUPPORTED */
static void
png_read_filter_row_sub(png_row_infop row_info, png_bytep row,
png_const_bytep prev_row)
{
png_size_t i;
png_size_t istop = row_info->rowbytes;
unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
png_bytep rp = row + bpp;
PNG_UNUSED(prev_row)
for (i = bpp; i < istop; i++)
{
*rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
rp++;
}
}
static void
png_read_filter_row_up(png_row_infop row_info, png_bytep row,
png_const_bytep prev_row)
{
png_size_t i;
png_size_t istop = row_info->rowbytes;
png_bytep rp = row;
png_const_bytep pp = prev_row;
for (i = 0; i < istop; i++)
{
*rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
rp++;
}
}
static void
png_read_filter_row_avg(png_row_infop row_info, png_bytep row,
png_const_bytep prev_row)
{
png_size_t i;
png_bytep rp = row;
png_const_bytep pp = prev_row;
unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
png_size_t istop = row_info->rowbytes - bpp;
for (i = 0; i < bpp; i++)
{
*rp = (png_byte)(((int)(*rp) +
((int)(*pp++) / 2 )) & 0xff);
rp++;
}
for (i = 0; i < istop; i++)
{
*rp = (png_byte)(((int)(*rp) +
(int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
rp++;
}
}
static void
png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row,
png_const_bytep prev_row)
{
png_bytep rp_end = row + row_info->rowbytes;
int a, c;
/* First pixel/byte */
c = *prev_row++;
a = *row + c;
*row++ = (png_byte)a;
/* Remainder */
while (row < rp_end)
{
int b, pa, pb, pc, p;
a &= 0xff; /* From previous iteration or start */
b = *prev_row++;
p = b - c;
pc = a - c;
# ifdef PNG_USE_ABS
pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
# else
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
# endif
/* Find the best predictor, the least of pa, pb, pc favoring the earlier
* ones in the case of a tie.
*/
if (pb < pa) pa = pb, a = b;
if (pc < pa) a = c;
/* Calculate the current pixel in a, and move the previous row pixel to c
* for the next time round the loop
*/
c = b;
a += *row;
*row++ = (png_byte)a;
}
}
static void
png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
png_const_bytep prev_row)
{
int bpp = (row_info->pixel_depth + 7) >> 3;
png_bytep rp_end = row + bpp;
/* Process the first pixel in the row completely (this is the same as 'up'
* because there is only one candidate predictor for the first row).
*/
while (row < rp_end)
{
int a = *row + *prev_row++;
*row++ = (png_byte)a;
}
/* Remainder */
rp_end += row_info->rowbytes - bpp;
while (row < rp_end)
{
int a, b, c, pa, pb, pc, p;
c = *(prev_row - bpp);
a = *(row - bpp);
b = *prev_row++;
p = b - c;
pc = a - c;
# ifdef PNG_USE_ABS
pa = abs(p);
pb = abs(pc);
pc = abs(p + pc);
# else
pa = p < 0 ? -p : p;
pb = pc < 0 ? -pc : pc;
pc = (p + pc) < 0 ? -(p + pc) : p + pc;
# endif
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_structrp 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_structrp pp)
{
unsigned int bpp = (pp->pixel_depth + 7) >> 3;
pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub;
pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up;
pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg;
if (bpp == 1)
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
png_read_filter_row_paeth_1byte_pixel;
else
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);
#endif
}
void /* PRIVATE */
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);
if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
pp->read_filter[filter-1](row_info, row, prev_row);
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
void /* PRIVATE */
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 /* check 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 (so, in the 'check' case this just
* counts up).
*/
avail_out += 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 /* checking */
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))
{
/* 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))
{
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 */
static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* 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)
{
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.
*/
memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
do
{
png_ptr->pass++;
if (png_ptr->pass >= 7)
break;
png_ptr->iwidth = (png_ptr->width +
png_pass_inc[png_ptr->pass] - 1 -
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
if (!(png_ptr->transformations & PNG_INTERLACE))
{
png_ptr->num_rows = (png_ptr->height +
png_pass_yinc[png_ptr->pass] - 1 -
png_pass_ystart[png_ptr->pass]) /
png_pass_yinc[png_ptr->pass];
}
else /* if (png_ptr->transformations & PNG_INTERLACE) */
break; /* libpng deinterlacing sees every row */
} while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0);
if (png_ptr->pass < 7)
return;
}
#endif /* PNG_READ_INTERLACING_SUPPORTED */
/* Here after at the end of the last row of the last pass. */
png_read_finish_IDAT(png_ptr);
}
#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
void /* PRIVATE */
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 */
static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
/* Offset to next interlace block */
static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
/* Start of interlace block in the y direction */
static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
/* 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");
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
png_init_read_transformations(png_ptr);
#endif
#ifdef PNG_READ_INTERLACING_SUPPORTED
if (png_ptr->interlaced)
{
if (!(png_ptr->transformations & PNG_INTERLACE))
png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
png_pass_ystart[0]) / png_pass_yinc[0];
else
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = (png_ptr->width +
png_pass_inc[png_ptr->pass] - 1 -
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
}
else
#endif /* PNG_READ_INTERLACING_SUPPORTED */
{
png_ptr->num_rows = png_ptr->height;
png_ptr->iwidth = png_ptr->width;
}
max_pixel_depth = png_ptr->pixel_depth;
/* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar 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
* separate places. They must all match. Innocent changes to the order of
* transformations can and will break libpng in a way that causes memory
* overwrites.
*
* TODO: fix this.
*/
#ifdef PNG_READ_PACK_SUPPORTED
if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
max_pixel_depth = 8;
#endif
#ifdef PNG_READ_EXPAND_SUPPORTED
if (png_ptr->transformations & PNG_EXPAND)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (png_ptr->num_trans)
max_pixel_depth = 32;
else
max_pixel_depth = 24;
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
if (max_pixel_depth < 8)
max_pixel_depth = 8;
if (png_ptr->num_trans)
max_pixel_depth *= 2;
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
{
if (png_ptr->num_trans)
{
max_pixel_depth *= 4;
max_pixel_depth /= 3;
}
}
}
#endif
#ifdef PNG_READ_EXPAND_16_SUPPORTED
if (png_ptr->transformations & PNG_EXPAND_16)
{
# 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->bit_depth < 16)
max_pixel_depth *= 2;
}
else
# endif
png_ptr->transformations &= ~PNG_EXPAND_16;
}
#endif
#ifdef PNG_READ_FILLER_SUPPORTED
if (png_ptr->transformations & (PNG_FILLER))
{
if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
{
if (max_pixel_depth <= 8)
max_pixel_depth = 16;
else
max_pixel_depth = 32;
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (max_pixel_depth <= 32)
max_pixel_depth = 32;
else
max_pixel_depth = 64;
}
}
#endif
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
if (png_ptr->transformations & PNG_GRAY_TO_RGB)
{
if (
#ifdef PNG_READ_EXPAND_SUPPORTED
(png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
#endif
#ifdef PNG_READ_FILLER_SUPPORTED
(png_ptr->transformations & (PNG_FILLER)) ||
#endif
png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
if (max_pixel_depth <= 16)
max_pixel_depth = 32;
else
max_pixel_depth = 64;
}
else
{
if (max_pixel_depth <= 8)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
max_pixel_depth = 32;
else
max_pixel_depth = 24;
}
else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
max_pixel_depth = 64;
else
max_pixel_depth = 48;
}
}
#endif
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
if (png_ptr->transformations & PNG_USER_TRANSFORM)
{
int user_pixel_depth = png_ptr->user_transform_depth *
png_ptr->user_transform_channels;
if (user_pixel_depth > max_pixel_depth)
max_pixel_depth = user_pixel_depth;
}
#endif
/* This value is stored in png_struct and double checked in the row read
* code.
*/
png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth;
png_ptr->transformed_pixel_depth = 0; /* calculated on demand */
/* Align the width on the next larger 8 pixels. Mainly used
* for interlacing
*/
row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
/* Calculate the maximum bytes needed, adding a byte and a pixel
* for safety's sake
*/
row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
1 + ((max_pixel_depth + 7) >> 3);
#ifdef PNG_MAX_MALLOC_64K
if (row_bytes > (png_uint_32)65536L)
png_error(png_ptr, "This image requires a row greater than 64KB");
#endif
if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
{
png_free(png_ptr, png_ptr->big_row_buf);
png_free(png_ptr, png_ptr->big_prev_row);
if (png_ptr->interlaced)
png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
row_bytes + 48);
else
png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
/* Use 16-byte aligned memory for row_buf with at least 16 bytes
* of padding before and after row_buf; treat prev_row similarly.
* NOTE: the alignment is to the start of the pixels, one beyond the start
* of the buffer, because of the filter byte. Prior to libpng 1.5.6 this
* was incorrect; the filter byte was aligned, which had the exact
* opposite effect of that intended.
*/
{
png_bytep temp = png_ptr->big_row_buf + 32;
int extra = (int)((temp - (png_bytep)0) & 0x0f);
png_ptr->row_buf = temp - extra - 1/*filter byte*/;
temp = png_ptr->big_prev_row + 32;
extra = (int)((temp - (png_bytep)0) & 0x0f);
png_ptr->prev_row = temp - extra - 1/*filter byte*/;
}
#else
/* Use 31 bytes of padding before and 17 bytes after row_buf. */
png_ptr->row_buf = png_ptr->big_row_buf + 31;
png_ptr->prev_row = png_ptr->big_prev_row + 31;
#endif
png_ptr->old_big_row_buf_size = row_bytes + 48;
}
#ifdef PNG_MAX_MALLOC_64K
if (png_ptr->rowbytes > 65535)
png_error(png_ptr, "This image requires a row greater than 64KB");
#endif
if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
png_error(png_ptr, "Row has too many bytes to allocate in memory");
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);
png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes);
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)
{
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, 0) != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg);
png_ptr->flags |= PNG_FLAG_ROW_INIT;
}
#endif /* PNG_READ_SUPPORTED */