/* pngrutil.c - utilities to read a PNG file * * Copyright (c) 2018-2024 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * 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
#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate interlacing - use pass (0 - 6) as index. */
/* Start of interlace block */ staticconst png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ staticconst png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ staticconst png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ staticconst png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
/* TODO: Move these arrays to a common utility module to avoid duplication. */ #endif
if (uval > PNG_UINT_31_MAX)
png_error(png_ptr, "PNG unsigned integer out of range");
return uval;
}
#ifdefined(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)
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 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 (png_int_32)uval;
uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ if ((uval & 0x80000000) == 0) /* no overflow */ return -(png_int_32)uval; /* The following has to be safe; this function only gets called on PNG data * and if we get here that data is invalid. 0 is the most safe value and * if not then an attacker would surely just generate a PNG with 0 instead.
*/ return 0;
}
/* 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 accommodate 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.)
*/ unsignedint val =
((unsignedint)(*buf) << 8) +
((unsignedint)(*(buf + 1)));
return (png_uint_16)val;
}
#endif/* READ_INT_FUNCTIONS */
/* Read and check the PNG file signature */ void/* PRIVATE */
png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
{
size_t num_checked, num_to_check;
/* Exit if the user application does not expect a signature. */ if (png_ptr->sig_bytes >= 8) return;
/* 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) != 0)
{ if (num_checked < 4 &&
png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
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;
/* 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);
/* 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;
/* Optionally skip data and then check the CRC. Depending on whether we * are reading an ancillary or critical chunk, and how the program has set * things up, we may calculate the CRC on the data and print a message. * Returns '1' if there was a CRC error, '0' otherwise.
*/ int/* PRIVATE */
png_crc_finish(png_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;
/* 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_ANCILLARY(png_ptr->chunk_name) != 0)
{ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
(PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
need_crc = 0;
}
#ifdefined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) /* Manage the read buffer; this simply reallocates the buffer if it is not small * enough (or if it is not allocated). The routine returns a pointer to the * buffer; if an error occurs and 'warn' is set the routine returns NULL, else * it will call png_error (via png_malloc) on failure. (warn == 2 means * 'silent').
*/ static png_bytep
png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn)
{
png_bytep buffer = png_ptr->read_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.
*/ staticint
png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
{ if (png_ptr->zowner != 0)
{ char msg[64];
PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); /* So the message that results is "<chunk> using zstream"; this is an * internal error, but is very useful for debugging. i18n requirements * are minimal.
*/
(void)png_safecat(msg, (sizeof msg), 4, " using zstream"); #if PNG_RELEASE_BUILD
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 an illusion: the original writer * of the PNG may have selected a lower window size, and we really must * follow that because, for systems with with limited capabilities, we * would otherwise reject the application's attempts to use a smaller window * size (zlib doesn't have an interface to say "this or lower"!). * * inflateReset2 was added to zlib 1.2.4; before this the window could not be * reset, therefore it is necessary to always allocate the maximum window * size with earlier zlibs just in case later compressed chunks need it.
*/
{ int ret; /* zlib return code */ #if ZLIB_VERNUM >= 0x1240 int window_bits = 0;
/* 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) != 0)
{ #if ZLIB_VERNUM >= 0x1240
ret = inflateReset2(&png_ptr->zstream, window_bits); #else
ret = inflateReset(&png_ptr->zstream); #endif
}
else
{ #if ZLIB_VERNUM >= 0x1240
ret = inflateInit2(&png_ptr->zstream, window_bits); #else
ret = inflateInit(&png_ptr->zstream); #endif
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON) /* Turn off validation of the ADLER32 checksum in IDAT chunks */
ret = inflateValidate(&png_ptr->zstream, 0); #endif
if (ret == Z_OK)
png_ptr->zowner = owner;
else
png_zstream_error(png_ptr, ret);
return ret;
}
#ifdef window_bits # undef window_bits #endif
}
#if ZLIB_VERNUM >= 0x1240 /* Handle the start of the inflate stream if we called inflateInit2(strm,0); * in this case some zlib versions skip validation of the CINFO field and, in * certain circumstances, libpng may end up displaying an invalid image, in * contrast to implementations that call zlib in the normal way (e.g. libpng * 1.5).
*/ int/* PRIVATE */
png_zlib_inflate(png_structrp png_ptr, int flush)
{ if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0)
{ if ((*png_ptr->zstream.next_in >> 4) > 7)
{
png_ptr->zstream.msg = "invalid window size (libpng)"; return Z_DATA_ERROR;
}
#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED #ifdefined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_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).
*/ staticint
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 */
/* 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);
}
/* 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 = PNG_INFLATE(png_ptr, 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).
*/ staticint
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;
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)
{
memset(text, 0, buffer_size);
ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/,
png_ptr->read_buffer + prefix_size, &lzsize,
text + prefix_size, newlength);
if (ret == Z_STREAM_END)
{ if (new_size == *newlength)
{ if (terminate != 0)
text[prefix_size + *newlength] = 0;
if (prefix_size > 0)
memcpy(text, png_ptr->read_buffer, prefix_size);
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;
}
}
elseif (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);
ret = PNG_UNEXPECTED_ZLIB_RETURN;
}
}
elseif (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;
#ifdef PNG_READ_iCCP_SUPPORTED /* Perform a partial read and decompress, producing 'avail_out' bytes and * reading from the current chunk as required.
*/ staticint
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);
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 = PNG_INFLATE(png_ptr, *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;
}
/* 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 max_palette_length, 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) == 0)
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.)
*/ elseif ((png_ptr->mode & PNG_HAVE_PLTE) != 0)
png_chunk_error(png_ptr, "duplicate");
elseif ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
{ /* 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) == 0)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); return;
}
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;
/* If the palette has 256 or fewer entries but is too large for the bit * depth, we don't issue an error, to preserve the behavior of previous * libpng versions. We silently truncate the unused extra palette entries * here.
*/ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
max_palette_length = (1 << png_ptr->bit_depth); else
max_palette_length = PNG_MAX_PALETTE_LENGTH;
if (num > max_palette_length)
num = max_palette_length;
#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, (png_uint_32) (length - (unsignedint)num * 3));
}
#ifndef PNG_READ_OPT_PLTE_SUPPORTED elseif (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */
{ /* If we don't want to use the data from an ancillary chunk, * we have two options: an error abort, or a warning and we * ignore the data in this chunk (which should be OK, since * it's considered ancillary for a RGB or RGBA image). * * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the * chunk type to determine whether to check the ancillary or the critical * flags.
*/ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0)
{ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) return;
else
png_chunk_error(png_ptr, "CRC error");
}
/* Otherwise, we (optionally) emit a warning and use the chunk. */ elseif ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0)
png_chunk_warning(png_ptr, "CRC error");
} #endif
/* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its * own copy of the palette. This has the side effect that when png_start_row * is called (this happens after any call to png_read_update_info) the * info_ptr palette gets changed. This is extremely unexpected and * confusing. * * Fix this by not sharing the palette in this way.
*/
png_set_PLTE(png_ptr, info_ptr, palette, num);
/* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before * IDAT. Prior to 1.6.0 this was not checked; instead the code merely * checked the apparent validity of a tRNS chunk inserted before PLTE on a * palette PNG. 1.6.0 attempts to rigorously follow the standard and * therefore does a benign error if the erroneous condition is detected *and* * cancels the tRNS if the benign error returns. The alternative is to * amend the standard since it would be rather hypocritical of the standards * maintainers to ignore it.
*/ #ifdef PNG_READ_tRNS_SUPPORTED if (png_ptr->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
}
/* If a colorspace error has already been output skip this chunk */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) 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)
{
png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
png_colorspace_sync(png_ptr, info_ptr);
png_chunk_benign_error(png_ptr, "too many profiles"); return;
}
#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) == 0)
png_chunk_error(png_ptr, "missing IHDR");
/* 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 keyword must be at least one character and there is a * terminator (0) byte and the compression method byte, and the * 'zlib' datastream is at least 11 bytes.
*/ if (length < 14)
{
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) != 0)
{
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;
/* The minimum 'zlib' stream is assumed to be just the 2 byte header, * 5 bytes minimum 'deflate' stream, and the 4 byte checksum.
*/ if (length < 11)
{
png_crc_finish(png_ptr, length);
png_chunk_benign_error(png_ptr, "too short"); return;
}
/* TODO: make the keyword checking common */ if (keyword_length >= 1 && keyword_length <= 79)
{ /* We only understand '0' compression - deflate - so if we get a * different value we can't safely decode the chunk.
*/ if (keyword_length+1 < read_length &&
keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE)
{
read_length -= keyword_length+2;
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.
*/
png_uint_32 profile_length = png_get_uint_32(profile_header);
if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
keyword, profile_length) != 0)
{ /* The length is apparently ok, so we can check the 132 * byte header.
*/ if (png_icc_check_header(png_ptr, &png_ptr->colorspace,
keyword, profile_length, profile_header,
png_ptr->color_type) != 0)
{ /* Now read the tag table; a variable size buffer is * needed at this point, allocate one for the whole * profile. The header check has already validated * that none of this stuff will overflow.
*/
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));
/* Still expect a buffer error because we expect * there to be some tag data!
*/ if (size == 0)
{ if (png_icc_check_tag_table(png_ptr,
&png_ptr->colorspace, keyword, profile_length,
profile) != 0)
{ /* The profile has been validated for basic * security issues, so read the whole thing in.
*/
size = profile_length - (sizeof profile_header)
- 12 * tag_count;
/* But otherwise allow extra data: */ elseif (size == 0)
{ if (length > 0)
{ /* This can be handled completely, so * keep going.
*/
png_chunk_warning(png_ptr, "extra compressed data");
}
png_crc_finish(png_ptr, length);
finished = 1;
# ifdefined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0 /* Check for a match against sRGB */
png_icc_set_sRGB(png_ptr,
&png_ptr->colorspace, profile,
png_ptr->zstream.adler); # endif
/* Steal the profile for info_ptr. */ if (info_ptr != NULL)
{
png_free_data(png_ptr, info_ptr,
PNG_FREE_ICCP, 0);
#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;
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) == 0)
png_chunk_error(png_ptr, "missing IHDR");
#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) != 0) 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 (length < 2U || entry_start > buffer + (length - 2U))
{
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 % (unsignedint)entry_size) != 0)
{
png_warning(png_ptr, "sPLT chunk has bad length"); return;
}
elseif (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{ if ((png_ptr->mode & PNG_HAVE_PLTE) == 0)
{ /* 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;
}
/* 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
/* 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 != NULL && info_ptr->num_palette != 0)
{ if (buf[0] >= info_ptr->num_palette)
{
png_chunk_benign_error(png_ptr, "invalid index"); return;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.