diff options
Diffstat (limited to 'pngrutil.c')
-rw-r--r-- | pngrutil.c | 796 |
1 files changed, 628 insertions, 168 deletions
diff --git a/pngrutil.c b/pngrutil.c index 3a51f2708..3a69a485d 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * libpng 1.0.5d - November 29, 1999 + * libpng 1.0.5h - December 10, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -136,6 +136,124 @@ png_crc_error(png_structp png_ptr) return (0); } +#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ + defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_sPLT_SUPPORTED) +/* + * Decompress trailing data in a chunk. The assumption is that chunkdata + * 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). + */ +png_charp png_decompress_chunk(png_structp png_ptr, int comp_type, + png_charp chunkdata, png_size_t chunklength, + png_size_t prefix_size) +{ + static char msg[] = "Error decoding compressed text"; + png_charp text = NULL; + png_size_t text_size = (chunklength - prefix_size); + + if (comp_type == PNG_TEXT_COMPRESSION_zTXt) + { + png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size); + png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size); + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + + text_size = 0; + text = NULL; + + while (png_ptr->zstream.avail_in) + { + int ret; + + ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + { + if (png_ptr->zstream.msg != NULL) + png_warning(png_ptr, png_ptr->zstream.msg); + else + png_warning(png_ptr, msg); + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + if (text == NULL) + { + text_size = prefix_size + sizeof(msg) + 1; + text = (png_charp)png_malloc(png_ptr, text_size); + png_memcpy(text, chunkdata, prefix_size); + } + + text[text_size - 1] = 0x00; + + /* Copy what we can of the error message into the text chunk */ + text_size = (png_size_t)(chunklength - (text - chunkdata) - 1); + text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + png_memcpy(text + prefix_size, msg, text_size + 1); + break; + } + if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) + { + if (text == NULL) + { + text_size = prefix_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out; + text = (png_charp)png_malloc(png_ptr, text_size + 1); + png_memcpy(text + prefix_size, png_ptr->zbuf, + text_size - prefix_size); + png_memcpy(text, chunkdata, prefix_size); + *(text + text_size) = 0x00; + } + else + { + png_charp tmp; + + tmp = text; + text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size + + png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); + png_memcpy(text, tmp, text_size); + png_free(png_ptr, tmp); + png_memcpy(text + text_size, png_ptr->zbuf, + (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); + text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; + *(text + text_size) = 0x00; + } + if (ret == Z_STREAM_END) + break; + else + { + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + } + } + } + + inflateReset(&png_ptr->zstream); + png_ptr->zstream.avail_in = 0; + + png_free(png_ptr, chunkdata); + chunkdata = text; + } + else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */ + { +#if !defined(PNG_NO_STDIO) + char umsg[50]; + + sprintf(umsg, "Unknown zTXt compression type %d", comp_type); + png_warning(png_ptr, umsg); +#else + png_warning(png_ptr, "Unknown zTXt compression type"); +#endif + + /* Copy what we can of the error message into the text chunk */ + text_size = (png_size_t)(chunklength - (text - chunkdata)); + text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); + png_memcpy(text, msg, text_size); + } + + return chunkdata; +} +#endif /* read and check the IDHR chunk */ void @@ -378,7 +496,9 @@ void png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_uint_32 igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED float file_gamma; +#endif png_byte buf[4]; png_debug(1, "in png_handle_gAMA\n"); @@ -424,7 +544,7 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) - if(fabs((float)igamma - 45455.)>500.) + if(igamma < 45000L || igamma > 46000L) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); @@ -435,11 +555,16 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_FLOATING_POINT_SUPPORTED file_gamma = (float)igamma / (float)100000.0; #ifdef PNG_READ_GAMMA_SUPPORTED png_ptr->gamma = file_gamma; #endif png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif } #endif @@ -514,8 +639,11 @@ void png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_byte buf[4]; - png_uint_32 val; +#ifdef PNG_FLOATING_POINT_SUPPORTED float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_uint_32 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; png_debug(1, "in png_handle_cHRM\n"); @@ -550,15 +678,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - white_x = (float)val / (float)100000.0; + int_x_white = png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - white_y = (float)val / (float)100000.0; + int_y_white = png_get_uint_32(buf); - if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || - white_x + white_y > 1.0) + if (int_x_white > 80000L || int_y_white > 80000L || + int_x_white + int_y_white > 100000L) { png_warning(png_ptr, "Invalid cHRM white point"); png_crc_finish(png_ptr, 24); @@ -566,15 +692,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - red_x = (float)val / (float)100000.0; + int_x_red = png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - red_y = (float)val / (float)100000.0; + int_y_red = png_get_uint_32(buf); - if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 || - red_x + red_y > 1.0) + if (int_x_red > 80000L || int_y_red > 80000L || + int_x_red + int_y_red > 100000L) { png_warning(png_ptr, "Invalid cHRM red point"); png_crc_finish(png_ptr, 16); @@ -582,15 +706,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - green_x = (float)val / (float)100000.0; + int_x_green = png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - green_y = (float)val / (float)100000.0; + int_y_green = png_get_uint_32(buf); - if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 || - green_x + green_y > 1.0) + if (int_x_green > 80000L || int_y_green > 80000L || + int_x_green + int_y_green > 100000L) { png_warning(png_ptr, "Invalid cHRM green point"); png_crc_finish(png_ptr, 8); @@ -598,20 +720,28 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - blue_x = (float)val / (float)100000.0; + int_x_blue = png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - blue_y = (float)val / (float)100000.0; + int_y_blue = png_get_uint_32(buf); - if (blue_x < (float)0 || blue_x > (float)0.8 || blue_y < (float)0 || - blue_y > (float)0.8 || blue_x + blue_y > (float)1.0) + if (int_x_blue > 80000L || int_y_blue > 80000L || + int_x_blue + int_y_blue > 100000L) { png_warning(png_ptr, "Invalid cHRM blue point"); png_crc_finish(png_ptr, 0); return; } +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif if (png_crc_finish(png_ptr, 0)) return; @@ -619,31 +749,45 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) { - if (fabs(white_x - (float).3127) > (float).001 || - fabs(white_y - (float).3290) > (float).001 || - fabs( red_x - (float).6400) > (float).001 || - fabs( red_y - (float).3300) > (float).001 || - fabs(green_x - (float).3000) > (float).001 || - fabs(green_y - (float).6000) > (float).001 || - fabs( blue_x - (float).1500) > (float).001 || - fabs( blue_y - (float).0600) > (float).001) + if (abs((int)int_x_white - 31270L) > 1000 || + abs((int)int_y_white - 32900L) > 1000 || + abs((int) int_x_red - 64000L) > 1000 || + abs((int) int_y_red - 33000L) > 1000 || + abs((int)int_x_green - 30000L) > 1000 || + abs((int)int_y_green - 60000L) > 1000 || + abs((int) int_x_blue - 15000L) > 1000 || + abs((int) int_y_blue - 6000L) > 1000) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); #ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n", white_x, white_y, red_x, red_y); fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n", green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr,"wx=%d, wy=%d, rx=%d, ry=%d\n", + int_x_white, int_y_white, int_x_red, int_y_red); + fprintf(stderr,"gx=%d, gy=%d, bx=%d, by=%d\n", + int_x_green, int_y_green, int_x_blue, int_y_blue); #endif +#endif /* PNG_NO_CONSOLE_IO */ } return; } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_FLOATING_POINT_SUPPORTED png_set_cHRM(png_ptr, info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif } #endif @@ -652,6 +796,7 @@ void png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { int intent; + int igamma; png_byte buf[1]; png_debug(1, "in png_handle_sRGB\n"); @@ -695,27 +840,38 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=png_ptr->gamma * 100000.; +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + igamma=(int)png_ptr->int_gamma; +# endif +#endif if ((info_ptr->valid & PNG_INFO_gAMA)) - if(fabs((png_ptr->gamma*(float)100000.+.5)-45455.) > 500.) + if(igamma < 45000L || igamma > 46000L) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); #ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED fprintf(stderr,"gamma=%f\n",png_ptr->gamma); +#else + fprintf(stderr,"gamma=%d\n",png_ptr->int_gamma); +#endif #endif } #endif /* PNG_READ_gAMA_SUPPORTED */ #ifdef PNG_READ_cHRM_SUPPORTED if (info_ptr->valid & PNG_INFO_cHRM) - if (fabs(info_ptr->x_white - (float).3127) > (float).001 || - fabs(info_ptr->y_white - (float).3290) > (float).001 || - fabs( info_ptr->x_red - (float).6400) > (float).001 || - fabs( info_ptr->y_red - (float).3300) > (float).001 || - fabs(info_ptr->x_green - (float).3000) > (float).001 || - fabs(info_ptr->y_green - (float).6000) > (float).001 || - fabs( info_ptr->x_blue - (float).1500) > (float).001 || - fabs( info_ptr->y_blue - (float).0600) > (float).001) + if (abs((int)info_ptr->int_x_white - 31270L) > 1000 || + abs((int)info_ptr->int_y_white - 32900L) > 1000 || + abs((int) info_ptr->int_x_red - 64000L) > 1000 || + abs((int) info_ptr->int_y_red - 33000L) > 1000 || + abs((int)info_ptr->int_x_green - 30000L) > 1000 || + abs((int)info_ptr->int_y_green - 60000L) > 1000 || + abs((int) info_ptr->int_x_blue - 15000L) > 1000 || + abs((int) info_ptr->int_y_blue - 6000L) > 1000) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); @@ -726,6 +882,195 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif /* PNG_READ_sRGB_SUPPORTED */ +#if defined(PNG_READ_iCCP_SUPPORTED) +void +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_charp chunkdata; + png_byte compression_type; + png_charp profile; + png_uint_32 skip = 0; + png_size_t slength, prefix_length; + + png_debug(1, "in png_handle_iCCP\n"); + + 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"); + + else 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 + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (profile = chunkdata; *profile; profile++) + /* empty loop to find end of name */ ; + ++profile; + + /* there should be at least one NUL (the compression type byte) + following the separator, and we should be on it */ + if (profile >= chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_error(png_ptr, "malformed iCCP chunk"); + } + + /* compression should always be zero */ + compression_type = *profile++; + + prefix_length = profile - chunkdata; + chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata, + slength, prefix_length); + + png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type, + chunkdata + prefix_length, png_strlen(chunkdata + prefix_length)); + png_free(png_ptr, chunkdata); +} +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#if defined(PNG_READ_sPLT_SUPPORTED) +void +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 chunkdata; + png_bytep entry_start; + png_spalette new_palette; + int data_length, entry_size, i; + png_uint_32 skip = 0; + png_size_t slength; + + png_debug(1, "in png_handle_sPLT\n"); + + 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; + } + 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 sPLT chunk"); + + else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sPLT) + { + png_warning(png_ptr, "Duplicate sPLT chunk"); + 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 + + chunkdata = (png_bytep)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, chunkdata, slength); + + if (png_crc_finish(png_ptr, skip)) + { + png_free(png_ptr, chunkdata); + return; + } + + chunkdata[slength] = 0x00; + + for (entry_start = 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 > chunkdata + slength) + { + png_free(png_ptr, chunkdata); + png_error(png_ptr, "malformed sPLT chunk"); + } + + new_palette.depth = *entry_start++; + entry_size = (new_palette.depth == 8 ? 6 : 10); + data_length = (slength - (entry_start - chunkdata)); + + /* integrity-check the data length */ + if (data_length % entry_size) + { + png_free(png_ptr, chunkdata); + png_error(png_ptr, "sPLT chunk has bad length"); + } + + new_palette.nentries = data_length / entry_size; + new_palette.entries = (png_spalette_entryp)png_malloc( + png_ptr, new_palette.nentries * sizeof(png_spalette_entry)); + + for (i = 0; i < new_palette.nentries; i++) + { + png_spalette_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; + } + + /* discard all chunk data except the name and stash that */ + new_palette.name = (png_charp)chunkdata; + + png_set_spalettes(png_ptr, info_ptr, &new_palette, 1); + + png_free(png_ptr, chunkdata); + png_free(png_ptr, new_palette.entries); +} +#endif /* PNG_READ_sPLT_SUPPORTED */ + #if defined(PNG_READ_tRNS_SUPPORTED) void png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) @@ -1012,7 +1357,7 @@ void png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_byte buf[9]; - png_uint_32 offset_x, offset_y; + png_int_32 offset_x, offset_y; int unit_type; png_debug(1, "in png_handle_oFFs\n"); @@ -1043,8 +1388,8 @@ png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (png_crc_finish(png_ptr, 0)) return; - offset_x = png_get_uint_32(buf); - offset_y = png_get_uint_32(buf + 4); + 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); } @@ -1167,6 +1512,99 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif +#if defined(PNG_READ_sCAL_SUPPORTED) +/* read the sCAL chunk */ +void +png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_charp unit, swidth, sheight, ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width=0., height=0.; + png_charp vp; +#endif + png_size_t slength; + + png_debug(1, "in png_handle_sCAL\n"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before sCAL"); + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_warning(png_ptr, "Invalid sCAL after IDAT"); + png_crc_finish(png_ptr, length); + return; + } + else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sCAL) + { + png_warning(png_ptr, "Duplicate sCAL chunk"); + png_crc_finish(png_ptr, length); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%d bytes)\n", + length + 1); + unit = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)unit, slength); + + if (png_crc_finish(png_ptr, 0)) + { + png_free(png_ptr, unit); + return; + } + + unit[slength] = 0x00; /* null terminate the last string */ + + png_debug(3, "Finding end of sCAL unit string\n"); + for (ep = unit; *ep; ep++) + /* empty loop */ ; + ep++; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + width = strtod(ep, &vp); + if (*vp) + png_error(png_ptr, "malformed width string in sCAL chunk"); +#endif + swidth = (png_charp)png_malloc(png_ptr, strlen(ep) + 1); + png_memcpy(swidth, ep, (png_size_t)strlen(ep)); + + for (ep = unit; *ep; ep++) + /* empty loop */ ; + ep++; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + height = strtod(ep, &vp); + if (*vp) + png_error(png_ptr, "malformed height string in sCAL chunk"); +#endif + sheight = (png_charp)png_malloc(png_ptr, strlen(ep) + 1); + png_memcpy(sheight, ep, (png_size_t)strlen(ep)); + + if (unit + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) + { + png_warning(png_ptr, "Invalid sCAL data"); + png_free(png_ptr, unit); + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); + return; + } + + +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, unit, width, height); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); +#endif + + png_free(png_ptr, unit); +} +#endif + #if defined(PNG_READ_tIME_SUPPORTED) void png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) @@ -1258,6 +1696,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; + text_ptr->lang = NULL; text_ptr->key = key; text_ptr->text = text; @@ -1273,12 +1712,11 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - static char msg[] = "Error decoding zTXt chunk"; png_textp text_ptr; - png_charp key; + png_charp chunkdata; png_charp text; int comp_type = PNG_TEXT_COMPRESSION_NONE; - png_size_t slength; + png_size_t slength, prefix_len; png_debug(1, "in png_handle_zTXt\n"); if (!(png_ptr->mode & PNG_HAVE_IHDR)) @@ -1298,153 +1736,154 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif - key = (png_charp)png_malloc(png_ptr, length + 1); + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)key, slength); + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, key); + png_free(png_ptr, chunkdata); return; } - key[slength] = 0x00; + chunkdata[slength] = 0x00; - for (text = key; *text; text++) + for (text = chunkdata; *text; text++) /* empty loop */ ; - /* zTXt must have some text after the keyword */ - if (text == key + slength) + /* zTXt must have some text after the chunkdataword */ + if (text == chunkdata + slength) { + comp_type = PNG_TEXT_COMPRESSION_NONE; png_warning(png_ptr, "Zero length zTXt chunk"); } - else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt) + else { - png_size_t text_size, key_size; - text++; + comp_type = *(++text); + text++; /* skip the compression byte */ + } + prefix_len = text - chunkdata; - png_ptr->zstream.next_in = (png_bytep)text; - png_ptr->zstream.avail_in = (uInt)(length - (text - key)); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata, + (png_size_t)length, prefix_len); - key_size = (png_size_t)(text - key); - text_size = 0; - text = NULL; + text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); + text_ptr->compression = comp_type; + text_ptr->lang = NULL; + text_ptr->key = chunkdata; + text_ptr->text = chunkdata + prefix_len; - while (png_ptr->zstream.avail_in) - { - int ret; + png_set_text(png_ptr, info_ptr, text_ptr, 1); - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_warning(png_ptr, png_ptr->zstream.msg); - else - png_warning(png_ptr, msg); - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; + png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); +} +#endif - if (text == NULL) - { - text_size = key_size + sizeof(msg) + 1; - text = (png_charp)png_malloc(png_ptr, (png_uint_32)text_size); - png_memcpy(text, key, key_size); - } +#if defined(PNG_READ_iTXt_SUPPORTED) +/* note: this does not correctly handle chunks that are > 64K under DOS */ +void +png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +{ + png_textp text_ptr; + png_charp chunkdata; + png_charp lang, text; + int comp_type = PNG_TEXT_COMPRESSION_NONE; + int comp_flag = 0; + png_size_t slength, prefix_len; - text[text_size - 1] = 0x00; + png_debug(1, "in png_handle_iTXt\n"); - /* Copy what we can of the error message into the text chunk */ - text_size = (png_size_t)(slength - (text - key) - 1); - text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); - png_memcpy(text + key_size, msg, text_size + 1); - break; - } - if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END) - { - if (text == NULL) - { - text = (png_charp)png_malloc(png_ptr, - (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out - + key_size + 1)); - png_memcpy(text + key_size, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - png_memcpy(text, key, key_size); - text_size = key_size + png_ptr->zbuf_size - - png_ptr->zstream.avail_out; - *(text + text_size) = 0x00; - } - else - { - png_charp tmp; - - tmp = text; - text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size + - png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1)); - png_memcpy(text, tmp, text_size); - png_free(png_ptr, tmp); - png_memcpy(text + text_size, png_ptr->zbuf, - (png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out; - *(text + text_size) = 0x00; - } - if (ret != Z_STREAM_END) - { - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - else - { - break; - } - } - } + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_error(png_ptr, "Missing IHDR before iTXt"); - inflateReset(&png_ptr->zstream); - png_ptr->zstream.avail_in = 0; + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; - png_free(png_ptr, key); - key = text; - text += key_size; +#ifdef PNG_MAX_MALLOC_64K + /* We will no doubt have problems with chunks even half this size, but + there is no hard and fast rule to tell us where to stop. */ + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr,"iTXt chunk too large to fit in memory"); + png_crc_finish(png_ptr, length); + return; } - else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */ +#endif + + chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + slength = (png_size_t)length; + png_crc_read(png_ptr, (png_bytep)chunkdata, slength); + if (png_crc_finish(png_ptr, 0)) { - png_size_t text_size; -#if !defined(PNG_NO_STDIO) - char umsg[50]; + png_free(png_ptr, chunkdata); + return; + } - sprintf(umsg, "Unknown zTXt compression type %d", comp_type); - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, "Unknown zTXt compression type"); -#endif + chunkdata[slength] = 0x00; - /* Copy what we can of the error message into the text chunk */ - text_size = (png_size_t)(slength - (text - key) - 1); - text_size = sizeof(msg) > text_size ? text_size : sizeof(msg); - png_memcpy(text, msg, text_size + 1); + for (lang = chunkdata; *lang; lang++) + /* empty loop */ ; + lang++; /* skip NUL separator */ + + /* iTXt must have a language tag and some text after the keyword */ + if (lang >= chunkdata + slength) + { + comp_type = PNG_TEXT_COMPRESSION_NONE; + png_warning(png_ptr, "Zero length iTXt chunk"); } + else + { + comp_flag = *lang++; + comp_type = *lang++; + } + + for (text = lang; *text; text++) + /* empty loop */ ; + text++; /* skip NUL separator */ + + prefix_len = text - chunkdata; + + if (comp_flag) + chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata, + (size_t)length, prefix_len); text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); - text_ptr->compression = comp_type; - text_ptr->key = key; - text_ptr->text = text; + text_ptr->compression = (png_byte)comp_type; + text_ptr->lang = NULL; + text_ptr->key = chunkdata; + text_ptr->text = chunkdata + prefix_len; png_set_text(png_ptr, info_ptr, text_ptr, 1); png_free(png_ptr, text_ptr->key); png_free(png_ptr, text_ptr); + png_free(png_ptr, chunkdata); +} +#endif + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +void +png_set_keep_unknown_chunks(png_structp png_ptr) +{ + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; } #endif /* This function is called when we haven't found a handler for a chunk. If there isn't a problem with the chunk itself (ie bad - chunk name, CRC, or a critical chunk), the chunk is silently ignored. */ + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ void png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { + png_uint_32 skip = 0; + png_debug(1, "in png_handle_unknown\n"); + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + /* In the future we can have code here that calls user-supplied * callback functions for unknown chunks before they are ignored or * cause an error. @@ -1460,11 +1899,32 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; - png_crc_finish(png_ptr, length); +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + strcpy(chunk.name, png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, chunk.data, length); + chunk.size = length; + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip = length; + png_crc_finish(png_ptr, skip); } /* This function is called to verify that a chunk name is valid. @@ -1715,11 +2175,11 @@ png_do_read_interlace { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; #endif - + png_debug(1,"in png_do_read_interlace\n"); if (row != NULL && row_info != NULL) { @@ -2060,20 +2520,20 @@ png_read_finish_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + png_debug(1, "in png_read_finish_row\n"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) @@ -2182,20 +2642,20 @@ png_read_start_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + int max_pixel_depth; png_uint_32 row_bytes; |