+#ifdef PNG_READ_iCCP_SUPPORTED
+void /* PRIVATE */
+png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_byte compression_type;
+ png_bytep pC;
+ png_charp profile;
+ png_uint_32 skip = 0;
+ png_uint_32 profile_size;
+ png_alloc_size_t profile_length;
+ png_size_t slength, prefix_length, data_length;
+
+ png_debug(1, "in png_handle_iCCP");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before iCCP");
+
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid iCCP after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place iCCP chunk");
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+ {
+ png_warning(png_ptr, "Duplicate iCCP chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "iCCP chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ return;
+ }
+
+ png_ptr->chunkdata[slength] = 0x00;
+
+ for (profile = png_ptr->chunkdata; *profile; profile++)
+ /* Empty loop to find end of name */ ;
+
+ ++profile;
+
+ /* There should be at least one zero (the compression type byte)
+ * following the separator, and we should be on it
+ */
+ if (profile >= png_ptr->chunkdata + slength - 1)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_warning(png_ptr, "Malformed iCCP chunk");
+ return;
+ }
+
+ /* Compression_type should always be zero */
+ compression_type = *profile++;
+
+ if (compression_type)
+ {
+ png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
+ compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
+ wrote nonzero) */
+ }
+
+ prefix_length = profile - png_ptr->chunkdata;
+ png_decompress_chunk(png_ptr, compression_type,
+ slength, prefix_length, &data_length);
+
+ profile_length = data_length - prefix_length;
+
+ if (prefix_length > data_length || profile_length < 4)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_warning(png_ptr, "Profile size field missing from iCCP chunk");
+ return;
+ }
+
+ /* Check the profile_size recorded in the first 32 bits of the ICC profile */
+ pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
+ profile_size = ((*(pC )) << 24) |
+ ((*(pC + 1)) << 16) |
+ ((*(pC + 2)) << 8) |
+ ((*(pC + 3)) );
+
+ /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
+ * because profile_size is a 32 bit value.
+ */
+ if (profile_size < profile_length)
+ profile_length = profile_size;
+
+ /* And the following guarantees that profile_size == profile_length. */
+ if (profile_size > profile_length)
+ {
+ PNG_WARNING_PARAMETERS(p)
+
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+
+ png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size);
+ png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length);
+ png_formatted_warning(png_ptr, p,
+ "Ignoring iCCP chunk with declared size = @1 and actual length = @2");
+ return;
+ }
+
+ png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
+ compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
+ profile_size);
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+}
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#ifdef PNG_READ_sPLT_SUPPORTED
+void /* PRIVATE */
+png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_bytep entry_start;
+ png_sPLT_t new_palette;
+ png_sPLT_entryp pp;
+ png_uint_32 data_length;
+ int entry_size, i;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+ png_uint_32 dl;
+ png_size_t max_dl;
+
+ png_debug(1, "in png_handle_sPLT");
+
+#ifdef PNG_USER_LIMITS_SUPPORTED
+
+ if (png_ptr->user_chunk_cache_max != 0)
+ {
+ if (png_ptr->user_chunk_cache_max == 1)
+ {
+ 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_error(png_ptr, "Missing IHDR before sPLT");
+
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sPLT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "sPLT chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+
+ /* WARNING: this may break if size_t is less than 32 bits; it is assumed
+ * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
+ * potential breakage point if the types in pngconf.h aren't exactly right.
+ */
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ return;
+ }
+
+ png_ptr->chunkdata[slength] = 0x00;
+
+ for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
+ entry_start++)
+ /* Empty loop to find end of name */ ;
+
+ ++entry_start;
+
+ /* A sample depth should follow the separator, and we should be on it */
+ if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ 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 (and use 'length', not 'slength' here for clarity -
+ * they are guaranteed to be the same, see the tests above.)
+ */
+ data_length = length - (png_uint_32)(entry_start -
+ (png_bytep)png_ptr->chunkdata);
+
+ /* Integrity-check the data length */
+ if (data_length % entry_size)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_warning(png_ptr, "sPLT chunk has bad length");
+ return;
+ }
+
+ dl = (png_int_32)(data_length / entry_size);
+ max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry);
+
+ 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 * png_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_ptr->chunkdata;
+
+ png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
+
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_free(png_ptr, new_palette.entries);
+}
+#endif /* PNG_READ_sPLT_SUPPORTED */
+
+#ifdef PNG_READ_tRNS_SUPPORTED
+void /* PRIVATE */