+#if defined(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, 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)) );
+
+ if (profile_size < profile_length)
+ profile_length = profile_size;
+
+ if (profile_size > profile_length)
+ {
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ png_warning(png_ptr, "Ignoring truncated iCCP profile.");
+ return;
+ }
+
+ png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
+ compression_type, png_ptr->chunkdata + prefix_length, profile_length);
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+}
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#if defined(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;
+#ifdef PNG_NO_POINTER_INDEXING
+ png_sPLT_entryp pp;
+#endif
+ int data_length, entry_size, i;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_sPLT");
+
+ 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);
+ 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);
+ data_length = (slength - (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;
+ }
+
+ new_palette.nentries = (png_int_32) ( data_length / entry_size);
+ if ((png_uint_32) new_palette.nentries >
+ (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
+ {
+ png_warning(png_ptr, "sPLT chunk too long");
+ return;
+ }
+ 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;
+ }
+
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0; i < new_palette.nentries; i++)
+ {
+ png_sPLT_entryp 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->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 */
+