This repository has been archived on 2023-11-11. You can view files and clone it, but cannot push or open issues or pull requests.
libpng/pngread.c

720 lines
22 KiB
C
Raw Normal View History

1995-07-20 07:43:20 +00:00
/* pngread.c - read a png file
1996-01-26 07:38:47 +00:00
libpng 1.0 beta 2 - version 0.88
1995-07-20 07:43:20 +00:00
For conditions of distribution and use, see copyright notice in png.h
1996-01-16 07:51:56 +00:00
Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
1996-01-26 07:38:47 +00:00
January 25, 1996
1995-07-20 07:43:20 +00:00
*/
#define PNG_INTERNAL
#include "png.h"
/* initialize png structure for reading, and allocate any memory needed */
void
1995-12-19 09:22:19 +00:00
png_read_init(png_structp png_ptr)
1995-07-20 07:43:20 +00:00
{
1996-01-16 07:51:56 +00:00
jmp_buf tmp_jmp;
png_msg_ptr error_fn;
png_msg_ptr warning_fn;
png_voidp msg_ptr;
1995-12-19 09:22:19 +00:00
1996-01-16 07:51:56 +00:00
png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
error_fn = png_ptr->error_fn;
warning_fn = png_ptr->warning_fn;
msg_ptr = png_ptr->msg_ptr;
1995-12-19 09:22:19 +00:00
1996-01-16 07:51:56 +00:00
png_memset(png_ptr, 0, sizeof (png_struct));
1995-07-20 07:43:20 +00:00
1996-01-16 07:51:56 +00:00
png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
png_ptr->error_fn = error_fn;
png_ptr->warning_fn = warning_fn;
png_ptr->msg_ptr = msg_ptr;
1995-07-20 07:43:20 +00:00
png_ptr->zbuf_size = PNG_ZBUF_SIZE;
png_ptr->zbuf = png_large_malloc(png_ptr, png_ptr->zbuf_size);
1996-01-16 07:51:56 +00:00
png_ptr->zstream = (z_stream *)png_malloc(png_ptr, sizeof (z_stream));
png_ptr->zstream->zalloc = png_zalloc;
1995-07-20 07:43:20 +00:00
png_ptr->zstream->zfree = png_zfree;
1996-01-16 07:51:56 +00:00
png_ptr->zstream->opaque = (voidpf)png_ptr;
inflateInit(png_ptr->zstream);
1995-07-20 07:43:20 +00:00
png_ptr->zstream->next_out = png_ptr->zbuf;
png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
}
/* read the information before the actual image data. */
void
1995-12-19 09:22:19 +00:00
png_read_info(png_structp png_ptr, png_infop info)
1995-07-20 07:43:20 +00:00
{
png_byte chunk_start[8];
png_uint_32 length;
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 8);
if (png_memcmp(chunk_start, png_sig, 8))
png_error(png_ptr, "Not a Png File");
1995-07-20 07:43:20 +00:00
while (1)
{
png_uint_32 crc;
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 8);
1995-07-20 07:43:20 +00:00
length = png_get_uint_32(chunk_start);
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, chunk_start + 4, 4);
1995-12-19 09:22:19 +00:00
if (!png_memcmp(chunk_start + 4, png_IHDR, 4))
1995-07-20 07:43:20 +00:00
{
1996-01-16 07:51:56 +00:00
if (png_ptr->mode != PNG_BEFORE_IHDR)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place IHDR");
1995-07-20 07:43:20 +00:00
png_handle_IHDR(png_ptr, info, length);
png_ptr->mode = PNG_HAVE_IHDR;
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_PLTE, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Missing IHDR");
1995-07-20 07:43:20 +00:00
1995-09-26 10:22:39 +00:00
#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
png_crc_skip(png_ptr, length);
else
#else
{
png_handle_PLTE(png_ptr, info, length);
1996-01-16 07:51:56 +00:00
}
1995-09-26 10:22:39 +00:00
#endif
1995-07-20 07:43:20 +00:00
png_ptr->mode = PNG_HAVE_PLTE;
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_IDAT, 4))
1995-09-26 10:22:39 +00:00
{
png_ptr->idat_size = length;
png_ptr->mode = PNG_HAVE_IDAT;
break;
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_IEND, 4))
1995-09-26 10:22:39 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "No Image in File");
1995-09-26 10:22:39 +00:00
}
#if defined(PNG_READ_gAMA_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_gAMA, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR)
1996-01-16 07:51:56 +00:00
png_error(png_ptr, "Out of Place PLTE");
1995-07-20 07:43:20 +00:00
png_handle_gAMA(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_sBIT_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_sBIT, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place sBIT");
1995-07-20 07:43:20 +00:00
png_handle_sBIT(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_cHRM_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_cHRM, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR)
1996-01-16 07:51:56 +00:00
png_error(png_ptr, "Out of Place cHRM");
1995-07-20 07:43:20 +00:00
png_handle_cHRM(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_tRNS_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tRNS, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR &&
png_ptr->mode != PNG_HAVE_PLTE)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place tRNS");
1995-07-20 07:43:20 +00:00
png_handle_tRNS(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_bKGD_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_bKGD, 4))
1995-07-20 07:43:20 +00:00
{
1996-01-16 07:51:56 +00:00
if (png_ptr->mode != PNG_HAVE_IHDR &&
1995-07-20 07:43:20 +00:00
png_ptr->mode != PNG_HAVE_PLTE)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place bKGD");
1995-07-20 07:43:20 +00:00
png_handle_bKGD(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_hIST_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_hIST, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_PLTE)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place hIST");
1995-07-20 07:43:20 +00:00
png_handle_hIST(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_pHYs_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_pHYs, 4))
1996-01-16 07:51:56 +00:00
{
1995-07-20 07:43:20 +00:00
if (png_ptr->mode != PNG_HAVE_IHDR &&
png_ptr->mode != PNG_HAVE_PLTE)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place pHYs");
1995-07-20 07:43:20 +00:00
png_handle_pHYs(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_oFFs_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_oFFs, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode != PNG_HAVE_IHDR &&
png_ptr->mode != PNG_HAVE_PLTE)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place oFFs");
1995-07-20 07:43:20 +00:00
png_handle_oFFs(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_tIME_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tIME, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place tIME");
1995-07-20 07:43:20 +00:00
png_handle_tIME(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_tEXt_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tEXt, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place tEXt");
1995-07-20 07:43:20 +00:00
png_handle_tEXt(png_ptr, info, length);
1996-01-16 07:51:56 +00:00
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_zTXt_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_zTXt, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place zTXt");
1995-07-20 07:43:20 +00:00
png_handle_zTXt(png_ptr, info, length);
}
1995-09-26 10:22:39 +00:00
#endif
1995-07-20 07:43:20 +00:00
else
{
1995-09-26 10:22:39 +00:00
if ((chunk_start[4] & 0x20) == 0)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Unknown Critical Chunk");
1995-07-20 07:43:20 +00:00
png_crc_skip(png_ptr, length);
}
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 4);
1995-07-20 07:43:20 +00:00
crc = png_get_uint_32(chunk_start);
if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
(png_ptr->crc & 0xffffffffL))
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Bad CRC value");
1995-07-20 07:43:20 +00:00
}
}
1995-09-26 10:22:39 +00:00
/* optional call to update the users info structure */
void
1995-12-19 09:22:19 +00:00
png_read_update_info(png_structp png_ptr, png_infop info_ptr)
1995-09-26 10:22:39 +00:00
{
if (!(png_ptr->row_init))
png_read_start_row(png_ptr);
png_read_transform_info(png_ptr, info_ptr);
}
1995-07-20 07:43:20 +00:00
/* initialize palette, background, etc, after transformations
are set, but before any reading takes place. This allows
the user to obtail a gamma corrected palette, for example.
If the user doesn't call this, we will do it ourselves. */
void
1995-12-19 09:22:19 +00:00
png_start_read_image(png_structp png_ptr)
1995-07-20 07:43:20 +00:00
{
1995-09-26 10:22:39 +00:00
if (!(png_ptr->row_init))
png_read_start_row(png_ptr);
1995-07-20 07:43:20 +00:00
}
void
1995-12-19 09:22:19 +00:00
png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
1995-07-20 07:43:20 +00:00
{
int ret;
if (!(png_ptr->row_init))
png_read_start_row(png_ptr);
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_INTERLACING_SUPPORTED)
1995-07-20 07:43:20 +00:00
/* 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 & 7)
{
if (dsp_row)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
1996-01-16 07:51:56 +00:00
png_read_finish_row(png_ptr);
1995-07-20 07:43:20 +00:00
return;
}
break;
case 1:
if ((png_ptr->row_number & 7) || png_ptr->width < 5)
{
if (dsp_row)
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 & 7) != 4)
{
if (dsp_row && (png_ptr->row_number & 4))
1996-01-16 07:51:56 +00:00
png_combine_row(png_ptr, dsp_row,
1995-07-20 07:43:20 +00:00
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)
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)
1996-01-16 07:51:56 +00:00
{
1995-07-20 07:43:20 +00:00
if (dsp_row && (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)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
png_read_finish_row(png_ptr);
return;
}
break;
1996-01-16 07:51:56 +00:00
case 6:
1995-07-20 07:43:20 +00:00
if (!(png_ptr->row_number & 1))
{
png_read_finish_row(png_ptr);
return;
}
break;
}
}
1995-09-26 10:22:39 +00:00
#endif
1995-07-20 07:43:20 +00:00
if (png_ptr->mode != PNG_HAVE_IDAT)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid attempt to read row data");
1995-07-20 07:43:20 +00:00
png_ptr->zstream->next_out = png_ptr->row_buf;
png_ptr->zstream->avail_out = (uInt)png_ptr->irowbytes;
do
{
1996-01-16 07:51:56 +00:00
if (!(png_ptr->zstream->avail_in))
1995-07-20 07:43:20 +00:00
{
while (!png_ptr->idat_size)
{
png_byte buf[4];
png_uint_32 crc;
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, buf, 4);
1995-07-20 07:43:20 +00:00
crc = png_get_uint_32(buf);
if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
(png_ptr->crc & 0xffffffffL))
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Bad CRC value");
1995-07-20 07:43:20 +00:00
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, buf, 4);
1995-07-20 07:43:20 +00:00
png_ptr->idat_size = png_get_uint_32(buf);
png_reset_crc(png_ptr);
png_crc_read(png_ptr, buf, 4);
1996-01-16 07:51:56 +00:00
if (png_memcmp(buf, png_IDAT, 4))
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Not enough image data");
1995-07-20 07:43:20 +00:00
}
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_ptr->zstream->avail_in);
png_ptr->idat_size -= png_ptr->zstream->avail_in;
}
1996-01-16 07:51:56 +00:00
ret = inflate(png_ptr->zstream, Z_PARTIAL_FLUSH);
1995-07-20 07:43:20 +00:00
if (ret == Z_STREAM_END)
{
if (png_ptr->zstream->avail_out || png_ptr->zstream->avail_in ||
png_ptr->idat_size)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Extra compressed data");
1995-07-20 07:43:20 +00:00
png_ptr->mode = PNG_AT_LAST_IDAT;
1996-01-16 07:51:56 +00:00
break;
1995-07-20 07:43:20 +00:00
}
if (ret != Z_OK)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Compression Error");
1995-07-20 07:43:20 +00:00
} while (png_ptr->zstream->avail_out);
if (ret == Z_STREAM_END)
png_ptr->zlib_finished = 1;
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_ptr->row_info.width *
(png_uint_32)png_ptr->row_info.pixel_depth + 7) >> 3);
1996-01-16 07:51:56 +00:00
if (png_ptr->row_buf[0])
1995-07-20 07:43:20 +00:00
png_read_filter_row(&(png_ptr->row_info),
png_ptr->row_buf + 1, png_ptr->prev_row + 1,
(int)(png_ptr->row_buf[0]));
1995-09-26 10:22:39 +00:00
png_memcpy(png_ptr->prev_row, png_ptr->row_buf, (png_size_t)png_ptr->rowbytes + 1);
1995-07-20 07:43:20 +00:00
if (png_ptr->transformations)
png_do_read_transformations(png_ptr);
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_INTERLACING_SUPPORTED)
1995-07-20 07:43:20 +00:00
/* blow up interlaced rows to full size */
if (png_ptr->interlaced &&
(png_ptr->transformations & PNG_INTERLACE))
{
if (png_ptr->pass < 6)
png_do_read_interlace(&(png_ptr->row_info),
png_ptr->row_buf + 1, png_ptr->pass);
if (dsp_row)
png_combine_row(png_ptr, dsp_row,
png_pass_dsp_mask[png_ptr->pass]);
if (row)
png_combine_row(png_ptr, row,
png_pass_mask[png_ptr->pass]);
}
else
1995-09-26 10:22:39 +00:00
#endif
1995-07-20 07:43:20 +00:00
{
if (row)
png_combine_row(png_ptr, row, 0xff);
if (dsp_row)
png_combine_row(png_ptr, dsp_row, 0xff);
}
png_read_finish_row(png_ptr);
}
/* read a one or more rows of image data. If the image is interlaced,
and png_set_interlace_handling() has been called, the rows need to
to contain the contents of the rows from the previous pass. If
1996-01-16 07:51:56 +00:00
the image has alpha or transparency, and png_handle_alpha() has been
1995-07-20 07:43:20 +00:00
called, the rows contents must be initialized to the contents of the
screen. row holds the actual image, and pixels are placed in it
as they arrive. If the image is displayed after each pass, it will
appear to "sparkle" in. display_row can be used to display a
"chunky" progressive image, with finer detail added as it becomes
available. If you do not want this "chunky" display, you may pass
NULL for display_rows. If you do not want the sparkle display, and
you have not called png_handle_alpha(), you may pass NULL for rows.
If you have called png_handle_alpha(), and the image has either an
alpha channel or a transparency chunk, you must provide a buffer for
rows. In this case, you do not have to provide a display_rows buffer
also, but you may. If the image is not interlaced, or if you have
not called png_set_interlace_handling(), the display_row buffer will
1996-01-16 07:51:56 +00:00
be ignored, so pass NULL to it. */
1995-12-19 09:22:19 +00:00
1995-07-20 07:43:20 +00:00
void
1995-12-19 09:22:19 +00:00
png_read_rows(png_structp png_ptr, png_bytepp row,
1996-01-16 07:51:56 +00:00
png_bytepp display_row, png_uint_32 num_rows)
1995-07-20 07:43:20 +00:00
{
1996-01-16 07:51:56 +00:00
png_uint_32 i;
png_bytepp rp;
png_bytepp dp;
1995-07-20 07:43:20 +00:00
1995-11-28 17:22:13 +00:00
rp = row;
dp = display_row;
for (i = 0; i < num_rows; i++)
{
1996-01-16 07:51:56 +00:00
png_bytep rptr;
png_bytep dptr;
1995-11-28 17:22:13 +00:00
if (rp)
rptr = *rp;
else
rptr = NULL;
if (dp)
dptr = *dp;
else
dptr = NULL;
png_read_row(png_ptr, rptr, dptr);
1996-01-16 07:51:56 +00:00
if (row)
1995-12-19 09:22:19 +00:00
rp++;
1995-11-28 17:22:13 +00:00
if (display_row)
dp++;
}
1995-07-20 07:43:20 +00:00
}
/* read the image. If the image has an alpha channel or a transparency
1995-11-28 17:22:13 +00:00
chunk, and you have called png_handle_alpha(), you will need to
1995-07-20 07:43:20 +00:00
initialize the image to the current image that png will be overlaying.
Note that png_set_interlace_handling() has no effect on this call.
You only need to call this function once. If you desire to have
an image for each pass of a interlaced image, use png_read_rows() */
void
1995-12-19 09:22:19 +00:00
png_read_image(png_structp png_ptr, png_bytepp image)
1995-07-20 07:43:20 +00:00
{
png_uint_32 i;
int pass, j;
1996-01-16 07:51:56 +00:00
png_bytepp rp;
1995-07-20 07:43:20 +00:00
pass = png_set_interlace_handling(png_ptr);
for (j = 0; j < pass; j++)
{
rp = image;
for (i = 0; i < png_ptr->height; i++)
{
png_read_row(png_ptr, *rp, NULL);
rp++;
}
}
}
/* 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
1995-12-19 09:22:19 +00:00
png_read_end(png_structp png_ptr, png_infop info)
1995-07-20 07:43:20 +00:00
{
png_byte chunk_start[8];
png_uint_32 length;
png_uint_32 crc;
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 4);
1995-07-20 07:43:20 +00:00
crc = png_get_uint_32(chunk_start);
if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
(png_ptr->crc & 0xffffffffL))
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Bad CRC value");
1995-07-20 07:43:20 +00:00
do
{
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 8);
1995-07-20 07:43:20 +00:00
length = png_get_uint_32(chunk_start);
png_reset_crc(png_ptr);
png_calculate_crc(png_ptr, chunk_start + 4, 4);
1995-12-19 09:22:19 +00:00
if (!png_memcmp(chunk_start + 4, png_IHDR, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_PLTE, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_gAMA, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_sBIT, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_cHRM, 4))
1996-01-16 07:51:56 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tRNS, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_bKGD, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_hIST, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_IDAT, 4))
1995-07-20 07:43:20 +00:00
{
if (length > 0 || png_ptr->mode != PNG_AT_LAST_IDAT)
1996-01-16 07:51:56 +00:00
png_error(png_ptr, "too many IDAT's found");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_pHYs, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_oFFs, 4))
1995-07-20 07:43:20 +00:00
{
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "invalid chunk after IDAT");
1995-07-20 07:43:20 +00:00
}
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_tIME_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tIME, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place tIME");
1995-07-20 07:43:20 +00:00
if (info)
1996-01-16 07:51:56 +00:00
png_handle_tIME(png_ptr, info, length);
1995-07-20 07:43:20 +00:00
else
png_crc_skip(png_ptr, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_tEXt_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_tEXt, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place tEXt");
1995-07-20 07:43:20 +00:00
if (info)
png_handle_tEXt(png_ptr, info, length);
else
png_crc_skip(png_ptr, length);
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_zTXt_SUPPORTED)
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_zTXt, 4))
1995-07-20 07:43:20 +00:00
{
if (png_ptr->mode == PNG_BEFORE_IHDR ||
png_ptr->mode == PNG_AFTER_IEND)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Out of Place zTXt");
1995-07-20 07:43:20 +00:00
if (info)
png_handle_zTXt(png_ptr, info, length);
else
png_crc_skip(png_ptr, length);
}
1995-09-26 10:22:39 +00:00
#endif
1995-12-19 09:22:19 +00:00
else if (!png_memcmp(chunk_start + 4, png_IEND, 4))
1995-07-20 07:43:20 +00:00
{
png_ptr->mode = PNG_AFTER_IEND;
}
else
1996-01-16 07:51:56 +00:00
{
1995-09-26 10:22:39 +00:00
if ((chunk_start[4] & 0x20) == 0)
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Unknown Critical Chunk");
1995-07-20 07:43:20 +00:00
png_crc_skip(png_ptr, length);
}
1995-12-19 09:22:19 +00:00
png_read_data(png_ptr, chunk_start, 4);
1995-07-20 07:43:20 +00:00
crc = png_get_uint_32(chunk_start);
if (((crc ^ 0xffffffffL) & 0xffffffffL) !=
(png_ptr->crc & 0xffffffffL))
1995-12-19 09:22:19 +00:00
png_error(png_ptr, "Bad CRC value");
1996-01-16 07:51:56 +00:00
if (png_ptr->mode == PNG_AT_LAST_IDAT)
1995-07-20 07:43:20 +00:00
png_ptr->mode = PNG_AFTER_IDAT;
} while (png_ptr->mode != PNG_AFTER_IEND);
}
/* free all memory used by the read */
void
1995-12-19 09:22:19 +00:00
png_read_destroy(png_structp png_ptr, png_infop info, png_infop end_info)
1995-07-20 07:43:20 +00:00
{
int i;
jmp_buf tmp_jmp;
if (info)
1996-01-16 07:51:56 +00:00
{
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
1996-01-16 07:51:56 +00:00
for (i = 0; i < info->num_text; i++)
{
png_large_free(png_ptr, info->text[i].key);
}
1995-07-20 07:43:20 +00:00
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, info->text);
1995-09-26 10:22:39 +00:00
#endif
1996-01-16 07:51:56 +00:00
png_memset(info, 0, sizeof(png_info));
}
1995-07-20 07:43:20 +00:00
if (end_info)
{
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_tEXt_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED)
1996-01-16 07:51:56 +00:00
for (i = 0; i < end_info->num_text; i++)
1995-07-20 07:43:20 +00:00
{
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, end_info->text[i].key);
1995-07-20 07:43:20 +00:00
}
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, end_info->text);
1995-09-26 10:22:39 +00:00
#endif
png_memset(end_info, 0, sizeof(png_info));
1995-07-20 07:43:20 +00:00
}
png_large_free(png_ptr, png_ptr->zbuf);
png_large_free(png_ptr, png_ptr->row_buf);
png_large_free(png_ptr, png_ptr->prev_row);
1995-09-26 10:22:39 +00:00
#if defined(PNG_READ_DITHER_SUPPORTED)
1995-07-20 07:43:20 +00:00
png_large_free(png_ptr, png_ptr->palette_lookup);
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->dither_index);
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_table);
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_from_1);
png_large_free(png_ptr, png_ptr->gamma_to_1);
#endif
if (png_ptr->do_free & PNG_FREE_PALETTE)
png_large_free(png_ptr, png_ptr->palette);
#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_bKGD_SUPPORTED)
if (png_ptr->do_free & PNG_FREE_TRANS)
png_large_free(png_ptr, png_ptr->trans);
#endif
#if defined(PNG_READ_hIST_SUPPORTED)
if (png_ptr->do_free & PNG_FREE_HIST)
png_large_free(png_ptr, png_ptr->hist);
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED)
1995-07-20 07:43:20 +00:00
if (png_ptr->gamma_16_table)
{
for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
{
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_16_table[i]);
1995-07-20 07:43:20 +00:00
}
1996-01-16 07:51:56 +00:00
}
1995-09-26 10:22:39 +00:00
#endif
#if defined(PNG_READ_BACKGROUND_SUPPORTED)
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_16_table);
1995-07-20 07:43:20 +00:00
if (png_ptr->gamma_16_from_1)
1996-01-16 07:51:56 +00:00
{
1995-07-20 07:43:20 +00:00
for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
1996-01-16 07:51:56 +00:00
{
png_large_free(png_ptr, png_ptr->gamma_16_from_1[i]);
1995-07-20 07:43:20 +00:00
}
}
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_16_from_1);
1995-07-20 07:43:20 +00:00
if (png_ptr->gamma_16_to_1)
{
for (i = 0; i < (1 << (8 - png_ptr->gamma_shift)); i++)
{
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->gamma_16_to_1[i]);
1995-07-20 07:43:20 +00:00
}
1996-01-16 07:51:56 +00:00
}
png_large_free(png_ptr, png_ptr->gamma_16_to_1);
1995-09-26 10:22:39 +00:00
#endif
1995-11-28 17:22:13 +00:00
1996-01-16 07:51:56 +00:00
inflateEnd(png_ptr->zstream);
png_free(png_ptr, png_ptr->zstream);
1995-12-19 09:22:19 +00:00
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
1996-01-16 07:51:56 +00:00
png_large_free(png_ptr, png_ptr->save_buffer);
1995-12-19 09:22:19 +00:00
#endif
1996-01-16 07:51:56 +00:00
png_memcpy(tmp_jmp, png_ptr->jmpbuf, sizeof (jmp_buf));
png_memset(png_ptr, 0, sizeof (png_struct));
png_memcpy(png_ptr->jmpbuf, tmp_jmp, sizeof (jmp_buf));
1995-07-20 07:43:20 +00:00
}