/* pngset.c - storage of image information into info struct * * Copyright (c) 2018-2025 Cosmin Truta * Copyright (c) 1998-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 * * The functions here are used during reads to store data from the file * into the info struct, and during writes to store application data * into the info struct for writing into the file. This abstracts the * info struct and allows us to change the structure in the future.
*/
/* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in * version 1.2.1
*/
info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
if (info_ptr->hist == NULL)
{
png_warning(png_ptr, "Insufficient memory for hIST chunk data"); return;
}
for (i = 0; i < info_ptr->num_palette; i++)
info_ptr->hist[i] = hist[i];
void PNGAPI
png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type)
{
png_debug1(1, "in %s storage function", "IHDR");
length = strlen(purpose) + 1;
png_debug1(3, "allocating purpose for info (%lu bytes)",
(unsignedlong)length);
/* TODO: validate format of calibration name and unit name */
/* Check that the type matches the specification. */ if (type < 0 || type > 3)
{
png_chunk_report(png_ptr, "Invalid pCAL equation type",
PNG_CHUNK_WRITE_ERROR); return;
}
for (i = 0; i < nparams; i++)
{
length = strlen(params[i]) + 1;
png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
(unsignedlong)length);
/* Double check the unit (should never get here with an invalid * unit unless this is an API call.)
*/ if (unit != 1 && unit != 2)
png_error(png_ptr, "Invalid sCAL unit");
/* It may not actually be necessary to set png_ptr->palette here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. * * 1.6.0: the above statement appears to be incorrect; something has to set * the palette inside png_struct on read.
*/
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead * of num_palette entries, in case of an invalid PNG file or incorrect * call to png_set_PLTE() with too-large sample values.
*/
png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
if (num_palette > 0)
memcpy(png_ptr->palette, palette, (unsignedint)num_palette *
(sizeof (png_color)));
void PNGAPI
png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
{
png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
if (png_ptr == NULL || info_ptr == NULL) return;
if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,
srgb_intent) != 0)
{ /* This causes the gAMA and cHRM to be written too */
info_ptr->colorspace.flags |=
PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
}
if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return;
if (compression_type != PNG_COMPRESSION_TYPE_BASE)
png_app_error(png_ptr, "Invalid iCCP compression method");
/* Set the colorspace first because this validates the profile; do not * override previously set app cHRM or gAMA here (because likely as not the * application knows better than libpng what the correct values are.) Pass * the info_ptr color_type field to png_colorspace_set_ICC because in the * write case it has not yet been stored in png_ptr.
*/
{ int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
proflen, profile, info_ptr->color_type);
png_colorspace_sync_info(png_ptr, info_ptr);
/* Don't do any of the copying if the profile was bad, or inconsistent. */ if (result == 0) return;
/* But do write the gAMA and cHRM chunks from the profile. */
info_ptr->colorspace.flags |=
PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
}
/* Make sure we have enough space in the "text" array in info_struct * to hold all of the incoming text_ptr objects. This compare can't overflow * because max_text >= num_text (anyway, subtract of two positive integers * can't overflow in any case.)
*/ if (num_text > info_ptr->max_text - info_ptr->num_text)
{ int old_num_text = info_ptr->num_text; int max_text;
png_textp new_text = NULL;
/* Calculate an appropriate max_text, checking for overflow. */
max_text = old_num_text; if (num_text <= INT_MAX - max_text)
{
max_text += num_text;
/* Round up to a multiple of 8 */ if (max_text < INT_MAX-8)
max_text = (max_text + 8) & ~0x7;
else
max_text = INT_MAX;
/* Now allocate a new array and copy the old members in; this does all * the overflow checks.
*/
new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
info_ptr->text, old_num_text, max_text-old_num_text, sizeof *new_text));
}
if (new_text == NULL)
{
png_chunk_report(png_ptr, "too many text chunks",
PNG_CHUNK_WRITE_ERROR);
return 1;
}
png_free(png_ptr, info_ptr->text);
info_ptr->text = new_text;
info_ptr->free_me |= PNG_FREE_TEXT;
info_ptr->max_text = max_text; /* num_text is adjusted below as the entries are copied in */
png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
}
for (i = 0; i < num_text; i++)
{
size_t text_length, key_len;
size_t lang_len, lang_key_len;
png_textp textp = &(info_ptr->text[info_ptr->num_text]);
if (text_ptr[i].key == NULL) continue;
if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
{
png_chunk_report(png_ptr, "text compression mode is out of range",
PNG_CHUNK_WRITE_ERROR); continue;
}
if (trans_alpha != NULL)
{ /* It may not actually be necessary to set png_ptr->trans_alpha here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. * * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively * relies on png_set_tRNS storing the information in png_struct * (otherwise it won't be there for the code in pngrtran.c).
*/
#ifdef PNG_sPLT_SUPPORTED void PNGAPI
png_set_sPLT(png_const_structrp png_ptr,
png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) /* * entries - array of png_sPLT_t structures * to be added to the list of palettes * in the info structure. * * nentries - number of palette structures to be * added.
*/
{
png_sPLT_tp np;
/* Use the internal realloc function, which checks for all the possible * overflows. Notice that the parameters are (int) and (size_t)
*/
np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, sizeof *np));
if (np == NULL)
{ /* Out of memory or too many chunks */
png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); return;
}
/* Skip invalid input entries */ if (entries->name == NULL || entries->entries == NULL)
{ /* png_handle_sPLT doesn't do this, so this is an app error */
png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); /* Just skip the invalid entry */ continue;
}
np->depth = entries->depth;
/* In the event of out-of-memory just return - there's no point keeping * on trying to add sPLT chunks.
*/
length = strlen(entries->name) + 1;
np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
if (np->name == NULL) break;
memcpy(np->name, entries->name, length);
/* IMPORTANT: we have memory now that won't get freed if something else * goes wrong; this code must free it. png_malloc_array produces no * warnings; use a png_chunk_report (below) if there is an error.
*/
np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
entries->nentries, sizeof (png_sPLT_entry)));
np->nentries = entries->nentries; /* This multiply can't overflow because png_malloc_array has already * checked it when doing the allocation.
*/
memcpy(np->entries, entries->entries,
(unsignedint)entries->nentries * sizeof (png_sPLT_entry));
/* Note that 'continue' skips the advance of the out pointer and out * count, so an invalid entry is not added.
*/
info_ptr->valid |= PNG_INFO_sPLT;
++(info_ptr->splt_palettes_num);
++np;
++entries;
} while (--nentries);
if (nentries > 0)
png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
} #endif/* sPLT */
/* New in 1.6.0; copy the location and check it. This is an API * change; previously the app had to use the * png_set_unknown_chunk_location API below for each chunk.
*/ if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
{ /* Write struct, so unknown chunks come from the app */
png_app_warning(png_ptr, "png_set_unknown_chunks now expects a valid location"); /* Use the old behavior */
location = (png_byte)(png_ptr->mode &
(PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
}
/* This need not be an internal error - if the app calls * png_set_unknown_chunks on a read pointer it must get the location right.
*/ if (location == 0)
png_error(png_ptr, "invalid location in png_set_unknown_chunks");
/* Now reduce the location to the top-most set bit by removing each least * significant bit in turn.
*/ while (location != (location & -location))
location &= ~(location & -location);
/* The cast is safe because 'location' is a bit mask and only the low four * bits are significant.
*/ return (png_byte)location;
}
/* Check for the failure cases where support has been disabled at compile * time. This code is hardly ever compiled - it's here because * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this * code) but may be meaningless if the read or write handling of unknown * chunks is not compiled in.
*/ # if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_READ_SUPPORTED) if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
{
png_app_error(png_ptr, "no unknown chunk support on read");
return;
} # endif # if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_WRITE_SUPPORTED) if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
{
png_app_error(png_ptr, "no unknown chunk support on write");
return;
} # endif
/* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that * unknown critical chunks could be lost with just a warning resulting in * undefined behavior. Now png_chunk_report is used to provide behavior * appropriate to read or write.
*/
np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, sizeof *np));
if (np == NULL)
{
png_chunk_report(png_ptr, "too many unknown chunks",
PNG_CHUNK_WRITE_ERROR); return;
}
png_free(png_ptr, info_ptr->unknown_chunks);
info_ptr->unknown_chunks = np; /* safe because it is initialized */
info_ptr->free_me |= PNG_FREE_UNKN;
np += info_ptr->unknown_chunks_num;
/* Increment unknown_chunks_num each time round the loop to protect the * just-allocated chunk data.
*/ for (; num_unknowns > 0; --num_unknowns, ++unknowns)
{
memcpy(np->name, unknowns->name, (sizeof np->name));
np->name[(sizeof np->name)-1] = '\0';
np->location = check_location(png_ptr, unknowns->location);
if (np->data == NULL)
{
png_chunk_report(png_ptr, "unknown chunk: out of memory",
PNG_CHUNK_WRITE_ERROR); /* But just skip storing the unknown chunk */ continue;
}
/* These increments are skipped on out-of-memory for the data - the * unknown chunk entry gets overwritten if the png_chunk_report returns. * This is correct in the read case (the chunk is just dropped.)
*/
++np;
++(info_ptr->unknown_chunks_num);
}
}
void PNGAPI
png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)
{ /* This API is pretty pointless in 1.6.0 because the location can be set * before the call to png_set_unknown_chunks. * * TODO: add a png_app_warning in 1.7
*/ if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
chunk < info_ptr->unknown_chunks_num)
{ if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
{
png_app_error(png_ptr, "invalid unknown chunk location"); /* Fake out the pre 1.6.0 behavior: */ if (((unsignedint)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
location = PNG_AFTER_IDAT;
else
location = PNG_HAVE_IHDR; /* also undocumented */
}
/* Utility function: update the 'keep' state of a chunk if it is already in * the list, otherwise add it to the list.
*/ for (i=0; i<count; ++i, list += 5)
{ if (memcmp(list, add, 4) == 0)
{
list[4] = (png_byte)keep;
else/* num_chunks_in > 0 */
{ if (chunk_list == NULL)
{ /* Prior to 1.6.0 this was silently ignored, now it is an app_error * which can be switched off.
*/
png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
return;
}
num_chunks = (unsignedint)num_chunks_in;
}
old_num_chunks = png_ptr->num_chunk_list; if (png_ptr->chunk_list == NULL)
old_num_chunks = 0;
/* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
*/ if (num_chunks + old_num_chunks > UINT_MAX/5)
{
png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
return;
}
/* If these chunks are being reset to the default then no more memory is * required because add_one_chunk above doesn't extend the list if the 'keep' * parameter is the default.
*/ if (keep != 0)
{
new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
5 * (num_chunks + old_num_chunks)));
if (old_num_chunks > 0)
memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
}
/* Add the new chunks together with each one's handling code. If the chunk * already exists the code is updated, otherwise the chunk is added to the * end. (In libpng 1.6.0 order no longer matters because this code enforces * the earlier convention that the last setting is the one that is used.)
*/ if (new_list != NULL)
{
png_const_bytep inlist;
png_bytep outlist; unsignedint i;
/* Now remove any spurious 'default' entries. */
num_chunks = 0; for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
{ if (inlist[4])
{ if (outlist != inlist)
memcpy(outlist, inlist, 5);
outlist += 5;
++num_chunks;
}
}
/* This means the application has removed all the specialized handling. */ if (num_chunks == 0)
{ if (png_ptr->chunk_list != new_list)
png_free(png_ptr, new_list);
new_list = NULL;
}
}
else
num_chunks = 0;
png_ptr->num_chunk_list = num_chunks;
if (png_ptr->chunk_list != new_list)
{ if (png_ptr->chunk_list != NULL)
png_free(png_ptr, png_ptr->chunk_list);
# ifdef PNG_WRITE_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
{ if (png_ptr->zowner != 0)
{
png_warning(png_ptr, "Compression buffer size cannot be changed because it is in use");
return;
}
#ifndef __COVERITY__ /* Some compilers complain that this is always false. However, it * can be true when integer overflow happens.
*/ if (size > ZLIB_IO_MAX)
{
png_warning(png_ptr, "Compression buffer size limited to system maximum");
size = ZLIB_IO_MAX; /* must fit */
} #endif
if (size < 6)
{ /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH * if this is permitted.
*/
png_warning(png_ptr, "Compression buffer size cannot be reduced below 6");
#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI
png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
png_uint_32 user_height_max)
{
png_debug(1, "in png_set_user_limits");
/* Images with dimensions larger than these limits will be * rejected by png_set_IHDR(). To accept any PNG datastream * regardless of dimensions, set both limits to 0x7fffffff.
*/ if (png_ptr == NULL) return;
/* This function was added to libpng 1.4.0 */ void PNGAPI
png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
{
png_debug(1, "in png_set_chunk_cache_max");
if (png_ptr != NULL)
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
}
/* This function was added to libpng 1.4.1 */ void PNGAPI
png_set_chunk_malloc_max(png_structrp png_ptr,
png_alloc_size_t user_chunk_malloc_max)
{
png_debug(1, "in png_set_chunk_malloc_max");
#ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI
png_set_benign_errors(png_structrp png_ptr, int allowed)
{
png_debug(1, "in png_set_benign_errors");
/* If allowed is 1, png_benign_error() is treated as a warning. * * If allowed is 0, png_benign_error() is treated as an error (which * is the default behavior if png_set_benign_errors() is not called).
*/
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Whether to report invalid palette index; added at libng-1.5.10. * It is possible for an indexed (color-type==3) PNG file to contain * pixels with invalid (out-of-range) indexes if the PLTE chunk has * fewer entries than the image's bit-depth would allow. We recover * from this gracefully by filling any incomplete palette with zeros * (opaque black). By default, when this occurs libpng will issue * a benign error. This API can be used to override that behavior.
*/ void PNGAPI
png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
{
png_debug(1, "in png_set_check_for_invalid_index");
if (allowed > 0)
png_ptr->num_palette_max = 0;
else
png_ptr->num_palette_max = -1;
} #endif
#ifdefined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, * and if invalid, correct the keyword rather than discarding the entire * chunk. The PNG 1.0 specification requires keywords 1-79 characters in * length, forbids leading or trailing whitespace, multiple internal spaces, * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. * * The 'new_key' buffer must be 80 characters in size (for the keyword plus a * trailing '\0'). If this routine returns 0 then there was no keyword, or a * valid one could not be generated, and the caller must png_error.
*/
png_uint_32 /* PRIVATE */
png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
{ #ifdef PNG_WARNINGS_SUPPORTED
png_const_charp orig_key = key; #endif
png_uint_32 key_len = 0; int bad_character = 0; int space = 1;
elseif (space == 0)
{ /* A space or an invalid character when one wasn't seen immediately * before; output just a space.
*/
*new_key++ = 32; ++key_len; space = 1;
/* If the character was not a space then it is invalid. */ if (ch != 32)
bad_character = ch;
}
elseif (bad_character == 0)
bad_character = ch; /* just skip it, record the first error */
}
if (key_len > 0 && space != 0) /* trailing space */
{
--key_len; --new_key; if (bad_character == 0)
bad_character = 32;
}
/* Terminate the keyword */
*new_key = 0;
if (key_len == 0) return 0;
#ifdef PNG_WARNINGS_SUPPORTED /* Try to only output one warning per keyword: */ if (*key != 0) /* keyword too long */
png_warning(png_ptr, "keyword truncated");
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.