/* Read the end of the PNG file. Will not read past the end of the * file, will verify the end is accurate, and will read any comments * or time information at the end of the file, if info is not NULL. */ void PNGAPI png_read_end(png_structp png_ptr, png_infop info_ptr) { png_debug(1, "in png_read_end"); if (png_ptr == NULL) return; png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */ do { PNG_IHDR; PNG_IDAT; PNG_IEND; PNG_PLTE; #ifdef PNG_READ_bKGD_SUPPORTED PNG_bKGD; #endif #ifdef PNG_READ_cHRM_SUPPORTED PNG_cHRM; #endif #ifdef PNG_READ_gAMA_SUPPORTED PNG_gAMA; #endif #ifdef PNG_READ_hIST_SUPPORTED PNG_hIST; #endif #ifdef PNG_READ_iCCP_SUPPORTED PNG_iCCP; #endif #ifdef PNG_READ_iTXt_SUPPORTED PNG_iTXt; #endif #ifdef PNG_READ_oFFs_SUPPORTED PNG_oFFs; #endif #ifdef PNG_READ_pCAL_SUPPORTED PNG_pCAL; #endif #ifdef PNG_READ_pHYs_SUPPORTED PNG_pHYs; #endif #ifdef PNG_READ_sBIT_SUPPORTED PNG_sBIT; #endif #ifdef PNG_READ_sCAL_SUPPORTED PNG_sCAL; #endif #ifdef PNG_READ_sPLT_SUPPORTED PNG_sPLT; #endif #ifdef PNG_READ_sRGB_SUPPORTED PNG_sRGB; #endif #ifdef PNG_READ_tEXt_SUPPORTED PNG_tEXt; #endif #ifdef PNG_READ_tIME_SUPPORTED PNG_tIME; #endif #ifdef PNG_READ_tRNS_SUPPORTED PNG_tRNS; #endif #ifdef PNG_READ_zTXt_SUPPORTED PNG_zTXt; #endif png_uint_32 length = png_read_chunk_header(png_ptr); PNG_CONST png_bytep chunk_name = png_ptr->chunk_name; if (!png_memcmp(chunk_name, png_IHDR, 4)) png_handle_IHDR(png_ptr, info_ptr, length); else if (!png_memcmp(chunk_name, png_IEND, 4)) png_handle_IEND(png_ptr, info_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if (png_handle_as_unknown(png_ptr, chunk_name)) { if (!png_memcmp(chunk_name, png_IDAT, 4)) { if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) png_benign_error(png_ptr, "Too many IDATs found"); } png_handle_unknown(png_ptr, info_ptr, length); if (!png_memcmp(chunk_name, png_PLTE, 4)) png_ptr->mode |= PNG_HAVE_PLTE; } #endif else if (!png_memcmp(chunk_name, png_IDAT, 4)) { /* Zero length IDATs are legal after the last IDAT has been * read, but not after other chunks have been read. */ if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) png_benign_error(png_ptr, "Too many IDATs found"); png_crc_finish(png_ptr, length); } else if (!png_memcmp(chunk_name, png_PLTE, 4)) png_handle_PLTE(png_ptr, info_ptr, length); #ifdef PNG_READ_bKGD_SUPPORTED else if (!png_memcmp(chunk_name, png_bKGD, 4)) png_handle_bKGD(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (!png_memcmp(chunk_name, png_cHRM, 4)) png_handle_cHRM(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_gAMA_SUPPORTED else if (!png_memcmp(chunk_name, png_gAMA, 4)) png_handle_gAMA(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_hIST_SUPPORTED else if (!png_memcmp(chunk_name, png_hIST, 4)) png_handle_hIST(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (!png_memcmp(chunk_name, png_oFFs, 4)) png_handle_oFFs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (!png_memcmp(chunk_name, png_pCAL, 4)) png_handle_pCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (!png_memcmp(chunk_name, png_sCAL, 4)) png_handle_sCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (!png_memcmp(chunk_name, png_pHYs, 4)) png_handle_pHYs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (!png_memcmp(chunk_name, png_sBIT, 4)) png_handle_sBIT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (!png_memcmp(chunk_name, png_sRGB, 4)) png_handle_sRGB(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (!png_memcmp(chunk_name, png_iCCP, 4)) png_handle_iCCP(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (!png_memcmp(chunk_name, png_sPLT, 4)) png_handle_sPLT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (!png_memcmp(chunk_name, png_tEXt, 4)) png_handle_tEXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tIME_SUPPORTED else if (!png_memcmp(chunk_name, png_tIME, 4)) png_handle_tIME(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (!png_memcmp(chunk_name, png_tRNS, 4)) png_handle_tRNS(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (!png_memcmp(chunk_name, png_zTXt, 4)) png_handle_zTXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (!png_memcmp(chunk_name, png_iTXt, 4)) png_handle_iTXt(png_ptr, info_ptr, length); #endif else png_handle_unknown(png_ptr, info_ptr, length); } while (!(png_ptr->mode & PNG_HAVE_IEND)); }
void PNGAPI png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen) { png_charp new_iccp_name; png_bytep new_iccp_profile; png_size_t length; png_debug1(1, "in %s storage function", "iCCP"); 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; } length = strlen(name)+1; new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (new_iccp_name == NULL) { png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); return; } memcpy(new_iccp_name, name, length); new_iccp_profile = png_voidcast(png_bytep, png_malloc_warn(png_ptr, proflen)); if (new_iccp_profile == NULL) { png_free(png_ptr, new_iccp_name); png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); return; } memcpy(new_iccp_profile, profile, proflen); png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); info_ptr->iccp_proflen = proflen; info_ptr->iccp_name = new_iccp_name; info_ptr->iccp_profile = new_iccp_profile; info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; }
void PNGAPI png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) { PNG_IDAT; PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff}; PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff}; int ret; if (png_ptr == NULL) return; png_debug2(1, "in png_read_row (row %lu, pass %d)", (unsigned long) png_ptr->row_number, png_ptr->pass); if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Check for transforms that have been set but were defined out */ #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) if (png_ptr->transformations & PNG_INVERT_MONO) png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) if (png_ptr->transformations & PNG_FILLER) png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ !defined(PNG_READ_PACKSWAP_SUPPORTED) if (png_ptr->transformations & PNG_PACKSWAP) png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) if (png_ptr->transformations & PNG_PACK) png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) if (png_ptr->transformations & PNG_SHIFT) png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) if (png_ptr->transformations & PNG_BGR) png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) if (png_ptr->transformations & PNG_SWAP_BYTES) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } #ifdef PNG_READ_INTERLACING_SUPPORTED /* If interlaced and we do not need a new row, combine row and return */ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { switch (png_ptr->pass) { case 0: if (png_ptr->row_number & 0x07) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; case 1: if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; case 2: if ((png_ptr->row_number & 0x07) != 4) { if (dsp_row != NULL && (png_ptr->row_number & 4)) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; case 3: if ((png_ptr->row_number & 3) || png_ptr->width < 3) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; case 4: if ((png_ptr->row_number & 3) != 2) { if (dsp_row != NULL && (png_ptr->row_number & 2)) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; case 5: if ((png_ptr->row_number & 1) || png_ptr->width < 2) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); png_read_finish_row(png_ptr); return; } break; default: case 6: if (!(png_ptr->row_number & 1)) { png_read_finish_row(png_ptr); return; } break; } } #endif if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "Invalid attempt to read row data"); png_ptr->zstream.next_out = png_ptr->row_buf; png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); do { if (!(png_ptr->zstream.avail_in)) { while (!png_ptr->idat_size) { png_crc_finish(png_ptr, 0); png_ptr->idat_size = png_read_chunk_header(png_ptr); if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) png_error(png_ptr, "Not enough image data"); } png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_in = png_ptr->zbuf; if (png_ptr->zbuf_size > png_ptr->idat_size) png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; png_crc_read(png_ptr, png_ptr->zbuf, (png_size_t)png_ptr->zstream.avail_in); png_ptr->idat_size -= png_ptr->zstream.avail_in; } ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); if (ret == Z_STREAM_END) { if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in || png_ptr->idat_size) png_benign_error(png_ptr, "Extra compressed data"); png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; break; } if (ret != Z_OK) png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : "Decompression error"); } while (png_ptr->zstream.avail_out); png_ptr->row_info.color_type = png_ptr->color_type; png_ptr->row_info.width = png_ptr->iwidth; png_ptr->row_info.channels = png_ptr->channels; png_ptr->row_info.bit_depth = png_ptr->bit_depth; png_ptr->row_info.pixel_depth = png_ptr->pixel_depth; png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->row_info.width); if (png_ptr->row_buf[0]) png_read_filter_row(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr->prev_row + 1, (int)(png_ptr->row_buf[0])); png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); #ifdef PNG_MNG_FEATURES_SUPPORTED if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); } #endif if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA)) png_do_read_transformations(png_ptr); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Blow up interlaced rows to full size */ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { if (png_ptr->pass < 6) /* Old interface (pre-1.0.9): * png_do_read_interlace(&(png_ptr->row_info), * png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); */ png_do_read_interlace(png_ptr); if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, png_pass_dsp_mask[png_ptr->pass]); if (row != NULL) png_combine_row(png_ptr, row, png_pass_mask[png_ptr->pass]); } else #endif { if (row != NULL) png_combine_row(png_ptr, row, 0xff); if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 0xff); } png_read_finish_row(png_ptr); if (png_ptr->read_row_fn != NULL) (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); }
void /* PRIVATE */ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) { png_uint_32 chunk_name; #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED int keep; /* unknown handling method */ #endif /* First we make sure we have enough data for the 4-byte chunk name * and the 4-byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make * sure we have enough data in the buffer for the 4-byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; png_byte chunk_tag[4]; PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, chunk_tag, 4); png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } chunk_name = png_ptr->chunk_name; if (chunk_name == png_IDAT) { if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; /* If we reach an IDAT chunk, this means we have read all of the * header chunks, and we can start reading the image (or if this * is called after the image has been read - we have an error). */ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && (png_ptr->mode & PNG_HAVE_PLTE) == 0) png_error(png_ptr, "Missing PLTE before IDAT"); png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->process_mode = PNG_READ_IDAT_MODE; if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) if (png_ptr->push_length == 0) return; if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); } if (chunk_name == png_IHDR) { if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; png_push_have_end(png_ptr, info_ptr); } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } #endif else if (chunk_name == png_PLTE) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IDAT) { png_ptr->idat_size = png_ptr->push_length; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); png_ptr->zstream.avail_out = (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1; png_ptr->zstream.next_out = png_ptr->row_buf; return; } #ifdef PNG_READ_gAMA_SUPPORTED else if (png_ptr->chunk_name == png_gAMA) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (png_ptr->chunk_name == png_sBIT) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (png_ptr->chunk_name == png_cHRM) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (png_ptr->chunk_name == png_iCCP) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif else { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; }
void /* PRIVATE */ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) { PNG_IHDR; PNG_IDAT; PNG_IEND; PNG_PLTE; #ifdef PNG_READ_bKGD_SUPPORTED PNG_bKGD; #endif #ifdef PNG_READ_cHRM_SUPPORTED PNG_cHRM; #endif #ifdef PNG_READ_gAMA_SUPPORTED PNG_gAMA; #endif #ifdef PNG_READ_hIST_SUPPORTED PNG_hIST; #endif #ifdef PNG_READ_iCCP_SUPPORTED PNG_iCCP; #endif #ifdef PNG_READ_iTXt_SUPPORTED PNG_iTXt; #endif #ifdef PNG_READ_oFFs_SUPPORTED PNG_oFFs; #endif #ifdef PNG_READ_pCAL_SUPPORTED PNG_pCAL; #endif #ifdef PNG_READ_pHYs_SUPPORTED PNG_pHYs; #endif #ifdef PNG_READ_sBIT_SUPPORTED PNG_sBIT; #endif #ifdef PNG_READ_sCAL_SUPPORTED PNG_sCAL; #endif #ifdef PNG_READ_sRGB_SUPPORTED PNG_sRGB; #endif #ifdef PNG_READ_sPLT_SUPPORTED PNG_sPLT; #endif #ifdef PNG_READ_tEXt_SUPPORTED PNG_tEXt; #endif #ifdef PNG_READ_tIME_SUPPORTED PNG_tIME; #endif #ifdef PNG_READ_tRNS_SUPPORTED PNG_tRNS; #endif #ifdef PNG_READ_zTXt_SUPPORTED PNG_zTXt; #endif /* First we make sure we have enough data for the 4 byte chunk name * and the 4 byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make * sure we have enough data in the buffer for the 4 byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) { png_byte chunk_length[4]; if (png_ptr->buffer_size < 8) { png_push_save_buffer(png_ptr); return; } png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, png_ptr->chunk_name, 4); png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) if (png_ptr->mode & PNG_AFTER_IDAT) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4)) { if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; png_push_have_end(png_ptr, info_ptr); } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) png_ptr->mode |= PNG_HAVE_IDAT; png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) png_ptr->mode |= PNG_HAVE_PLTE; else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) { if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && !(png_ptr->mode & PNG_HAVE_PLTE)) png_error(png_ptr, "Missing PLTE before IDAT"); } } #endif else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) { /* If we reach an IDAT chunk, this means we have read all of the * header chunks, and we can start reading the image (or if this * is called after the image has been read - we have an error). */ if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && !(png_ptr->mode & PNG_HAVE_PLTE)) png_error(png_ptr, "Missing PLTE before IDAT"); if (png_ptr->mode & PNG_HAVE_IDAT) { if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) if (png_ptr->push_length == 0) return; if (png_ptr->mode & PNG_AFTER_IDAT) png_benign_error(png_ptr, "Too many IDATs found"); } png_ptr->idat_size = png_ptr->push_length; png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); png_ptr->zstream.avail_out = (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1; png_ptr->zstream.next_out = png_ptr->row_buf; return; } #ifdef PNG_READ_gAMA_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif else { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; }
void /* PRIVATE */ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { /* The caller checks for a non-zero buffer length. */ if (!(buffer_length > 0) || buffer == NULL) png_error(png_ptr, "No IDAT data (internal error)"); #ifdef PNG_READ_APNG_SUPPORTED /* If the app is not APNG-aware, decode only the first frame */ if ((png_ptr->apng_flags & PNG_APNG_APP) == 0 && png_ptr->num_frames_read > 0) { png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; return; } #endif /* This routine must process all the data it has been given * before returning, calling the row callback as required to * handle the uncompressed results. */ png_ptr->zstream.next_in = buffer; /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_in = (uInt)buffer_length; /* Keep going until the decompressed data is all processed * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { int ret; /* We have data for zlib, but we must check that zlib * has someplace to put the results. It doesn't matter * if we don't expect any results -- it may be the input * data is just the LZ end code. */ if (!(png_ptr->zstream.avail_out > 0)) { /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); png_ptr->zstream.next_out = png_ptr->row_buf; } /* Using Z_SYNC_FLUSH here means that an unterminated * LZ stream (a stream with a missing end code) can still * be handled, otherwise (Z_NO_FLUSH) a future zlib * implementation might defer output and therefore * change the current behavior (see comments in inflate.c * for why this doesn't happen at present with zlib 1.2.5). */ ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH); /* Check for any failure before proceeding. */ if (ret != Z_OK && ret != Z_STREAM_END) { /* Terminate the decompression. */ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; png_ptr->zowner = 0; /* This may be a truncated stream (missing or * damaged end code). Treat that as a warning. */ if (png_ptr->row_number >= png_ptr->num_rows || png_ptr->pass > 6) png_warning(png_ptr, "Truncated compressed data in IDAT"); else { if (ret == Z_DATA_ERROR) png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch"); else png_error(png_ptr, "Decompression error in IDAT"); } /* Skip the check on unprocessed input */ return; } /* Did inflate output any data? */ if (png_ptr->zstream.next_out != png_ptr->row_buf) { /* Is this unexpected data after the last row? * If it is, artificially terminate the LZ output * here. */ if (png_ptr->row_number >= png_ptr->num_rows || png_ptr->pass > 6) { /* Extra data. */ png_warning(png_ptr, "Extra compressed data in IDAT"); png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; png_ptr->zowner = 0; /* Do no more processing; skip the unprocessed * input check below. */ return; } /* Do we have a complete row? */ if (png_ptr->zstream.avail_out == 0) png_push_process_row(png_ptr); } /* And check for the end of the stream. */ if (ret == Z_STREAM_END) png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; } /* All the data should have been processed, if anything * is left at this point we have bytes of IDAT data * after the zlib end code. */ if (png_ptr->zstream.avail_in > 0) png_warning(png_ptr, "Extra compression data in IDAT"); }
/* Writes the end of the PNG file. If you don't want to write comments or * time information, you can pass NULL for info. If you already wrote these * in png_write_info(), do not write them again here. If you have long * comments, I suggest writing them here, and compressing them. */ void PNGAPI png_write_end(png_structp png_ptr, png_infop info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "No IDATs written into file"); #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED if (png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); #endif /* See if user wants us to write information chunks */ if (info_ptr != NULL) { #ifdef PNG_WRITE_TEXT_SUPPORTED int i; /* local index variable */ #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ if ((info_ptr->valid & PNG_INFO_tIME) && !(png_ptr->mode & PNG_WROTE_tIME)) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif #ifdef PNG_WRITE_TEXT_SUPPORTED /* Loop through comment chunks */ for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing trailer text chunk %d, type %d", i, info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write international chunk */ png_write_iTXt(png_ptr, info_ptr->text[i].compression, info_ptr->text[i].key, info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) { #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0, info_ptr->text[i].compression); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif } } #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED if (info_ptr->unknown_chunks_num) { png_unknown_chunk *up; png_debug(5, "writing extra chunks"); for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; up++) { int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && up->location && (up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { png_write_chunk(png_ptr, up->name, up->data, up->size); } } } #endif } png_ptr->mode |= PNG_AFTER_IDAT; /* Write end of PNG file */ png_write_IEND(png_ptr); /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application * experiences a problem, please try building libpng with * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to * png-mng-implement at lists.sf.net . */ #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED png_flush(png_ptr); # endif #endif }
void /* PRIVATE */ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) { png_uint_32 chunk_name; #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int keep; /* unknown handling method */ #endif /* First we make sure we have enough data for the 4 byte chunk name * and the 4 byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make * sure we have enough data in the buffer for the 4 byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) { png_byte chunk_length[4]; png_byte chunk_tag[4]; if (png_ptr->buffer_size < 8) { png_push_save_buffer(png_ptr); return; } png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, chunk_tag, 4); png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } chunk_name = png_ptr->chunk_name; #ifdef PNG_READ_APNG_SUPPORTED if (png_ptr->num_frames_read > 0 && png_ptr->num_frames_read < info_ptr->num_frames) { if (chunk_name == png_IDAT) { /* Discard trailing IDATs for the first frame */ if (png_ptr->mode & PNG_HAVE_fcTL || png_ptr->num_frames_read > 1) png_error(png_ptr, "out of place IDAT"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_crc_skip(png_ptr, png_ptr->push_length); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; return; } else if (chunk_name == png_fdAT) { if (png_ptr->buffer_size < 4) { png_push_save_buffer(png_ptr); return; } png_ensure_sequence_number(png_ptr, 4); if (!(png_ptr->mode & PNG_HAVE_fcTL)) { /* Discard trailing fdATs for frames other than the first */ if (png_ptr->num_frames_read < 2) png_error(png_ptr, "out of place fdAT"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_push_crc_skip(png_ptr, png_ptr->push_length); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; return; } else { /* frame data follows */ png_ptr->idat_size = png_ptr->push_length - 4; png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->process_mode = PNG_READ_IDAT_MODE; return; } } else if (chunk_name == png_fcTL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_read_reset(png_ptr); png_ptr->mode &= ~PNG_HAVE_fcTL; png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); if (!(png_ptr->mode & PNG_HAVE_fcTL)) png_error(png_ptr, "missing required fcTL chunk"); png_read_reinit(png_ptr, info_ptr); png_progressive_read_reset(png_ptr); if (png_ptr->frame_info_fn != NULL) (*(png_ptr->frame_info_fn))(png_ptr, png_ptr->num_frames_read); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; return; } else { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_warning(png_ptr, "Skipped (ignored) a chunk " "between APNG chunks"); png_push_crc_skip(png_ptr, png_ptr->push_length); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; return; } return; } #endif /* PNG_READ_APNG_SUPPORTED */ if (chunk_name == png_IDAT) { if (png_ptr->mode & PNG_AFTER_IDAT) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; /* If we reach an IDAT chunk, this means we have read all of the * header chunks, and we can start reading the image (or if this * is called after the image has been read - we have an error). */ if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && !(png_ptr->mode & PNG_HAVE_PLTE)) png_error(png_ptr, "Missing PLTE before IDAT"); png_ptr->mode |= PNG_HAVE_IDAT; if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) if (png_ptr->push_length == 0) return; if (png_ptr->mode & PNG_AFTER_IDAT) png_benign_error(png_ptr, "Too many IDATs found"); } if (chunk_name == png_IHDR) { if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; png_push_have_end(png_ptr, info_ptr); } #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } #endif else if (chunk_name == png_PLTE) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IDAT) { #ifdef PNG_READ_APNG_SUPPORTED png_have_info(png_ptr, info_ptr); #endif png_ptr->idat_size = png_ptr->push_length; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); png_ptr->zstream.avail_out = (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1; png_ptr->zstream.next_out = png_ptr->row_buf; return; } #ifdef PNG_READ_gAMA_SUPPORTED else if (png_ptr->chunk_name == png_gAMA) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (png_ptr->chunk_name == png_sBIT) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (png_ptr->chunk_name == png_cHRM) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (png_ptr->chunk_name == png_iCCP) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_APNG_SUPPORTED else if (chunk_name == png_acTL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_acTL(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_fcTL) { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_fcTL(png_ptr, info_ptr, png_ptr->push_length); } #endif /* PNG_READ_APNG_SUPPORTED */ else { if (png_ptr->push_length + 4 > png_ptr->buffer_size) { png_push_save_buffer(png_ptr); return; } png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; }