blob: f158db7338e0d8929157c80cd2437d23d3a0cbab [file] [log] [blame]
Glenn Randers-Pehrsone6474622006-03-04 16:50:47 -06001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngrutil.c - utilities to read a PNG file
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05004 * Last changed in libpng 1.4.0 [July 21, 2008]
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05006 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050010 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060011 * libpng itself during the course of reading an image.
12 */
Guy Schalnat0d580581995-07-20 02:43:20 -050013
Guy Schalnat0d580581995-07-20 02:43:20 -050014#include "png.h"
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050015#if defined(PNG_READ_SUPPORTED)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050016#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050017
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050018# define png_strtod(p,a,b) strtod(a,b)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060019png_uint_32 PNGAPI
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050020png_get_uint_31(png_structp png_ptr, png_bytep buf)
21{
Glenn Randers-Pehrsone826d7e2006-07-03 00:21:58 -050022#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050023 png_uint_32 i = png_get_uint_32(buf);
Glenn Randers-Pehrsone826d7e2006-07-03 00:21:58 -050024#else
25 /* Avoid an extra function call by inlining the result. */
26 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
27 ((png_uint_32)(*(buf + 1)) << 16) +
28 ((png_uint_32)(*(buf + 2)) << 8) +
29 (png_uint_32)(*(buf + 3));
30#endif
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050031 if (i > PNG_UINT_31_MAX)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050032 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050033 return (i);
34}
Andreas Dilger47a0c421997-05-16 02:46:07 -050035#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050036/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060037png_uint_32 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060038png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050039{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050040 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
Guy Schalnat0d580581995-07-20 02:43:20 -050041 ((png_uint_32)(*(buf + 1)) << 16) +
42 ((png_uint_32)(*(buf + 2)) << 8) +
43 (png_uint_32)(*(buf + 3));
44
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060045 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050046}
47
Glenn Randers-Pehrson86dc9812006-05-10 07:27:44 -050048#if defined(PNG_GET_INT_32_SUPPORTED)
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050049/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050050 * data is stored in the PNG file in two's complement format, and it is
51 * assumed that the machine format for signed integers is the same. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060052png_int_32 PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -050053png_get_int_32(png_bytep buf)
54{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050055 png_int_32 i = ((png_int_32)(*buf) << 24) +
Andreas Dilger47a0c421997-05-16 02:46:07 -050056 ((png_int_32)(*(buf + 1)) << 16) +
57 ((png_int_32)(*(buf + 2)) << 8) +
58 (png_int_32)(*(buf + 3));
59
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060060 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050061}
Glenn Randers-Pehrson86dc9812006-05-10 07:27:44 -050062#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -050063
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050064/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060065png_uint_16 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060066png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050067{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050068 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060069 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050070
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060071 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050072}
Andreas Dilger47a0c421997-05-16 02:46:07 -050073#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050074
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050075/* Read the chunk header (length + type name).
76 * Put the type name into png_ptr->chunk_name, and return the length.
77 */
78png_uint_32 /* PRIVATE */
79png_read_chunk_header(png_structp png_ptr)
80{
81 png_byte buf[8];
82 png_uint_32 length;
83
84#ifdef PNG_IO_STATE_SUPPORTED
85 /* Inform the I/O callback that the chunk header is being read.
86 * PNG_IO_CHUNK_HDR requires a single I/O call.
87 */
88 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
89#endif
90
91 /* read the length and the chunk name */
92 png_read_data(png_ptr, buf, 8);
93 length = png_get_uint_31(png_ptr, buf);
94
95 /* put the chunk name into png_ptr->chunk_name */
96 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
97
98 png_debug2(0, "Reading %s chunk, length = %lu\n",
99 png_ptr->chunk_name, length);
100
101 /* reset the crc and run it over the chunk name */
102 png_reset_crc(png_ptr);
103 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
104
105#ifdef PNG_IO_STATE_SUPPORTED
106 /* Inform the I/O callback that chunk data will (possibly) be read.
107 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
108 */
109 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
110#endif
111
112 return length;
113}
114
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500115/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500116void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500117png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500118{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500119 if (png_ptr == NULL) return;
Guy Schalnat6d764711995-12-19 03:22:19 -0600120 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500121 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500122}
123
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600124/* Optionally skip data and then check the CRC. Depending on whether we
125 are reading a ancillary or critical chunk, and how the program has set
Andreas Dilger47a0c421997-05-16 02:46:07 -0500126 things up, we may calculate the CRC on the data and print a message.
127 Returns '1' if there was a CRC error, '0' otherwise. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500128int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600129png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500130{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500131 png_size_t i;
132 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500133
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500134 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600135 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500136 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500137 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500138 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500139 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500140 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500141 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600142
Andreas Dilger47a0c421997-05-16 02:46:07 -0500143 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500145 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600146 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500147 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600148 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600149 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600150 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600151 }
152 else
153 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500154 png_chunk_benign_error(png_ptr, "CRC error");
155 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600156 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600157 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600158 }
159
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600160 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500161}
162
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600163/* Compare the CRC stored in the PNG file with that calculated by libpng from
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600164 the data it has read thus far. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500165int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600166png_crc_error(png_structp png_ptr)
167{
168 png_byte crc_bytes[4];
169 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500170 int need_crc = 1;
171
172 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
173 {
174 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
175 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
176 need_crc = 0;
177 }
178 else /* critical */
179 {
180 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
181 need_crc = 0;
182 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600183
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500184#ifdef PNG_IO_STATE_SUPPORTED
185 /* inform the I/O callback that the chunk CRC is being read */
186 /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */
187 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
188#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500189
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600190 png_read_data(png_ptr, crc_bytes, 4);
191
Andreas Dilger47a0c421997-05-16 02:46:07 -0500192 if (need_crc)
193 {
194 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600195 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500196 }
197 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600198 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600199}
200
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600201#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500202 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600203/*
204 * Decompress trailing data in a chunk. The assumption is that chunkdata
205 * points at an allocated area holding the contents of a chunk with a
206 * trailing compressed part. What we get back is an allocated area
207 * holding the original prefix part and an uncompressed version of the
208 * trailing part (the malloc area passed in is freed).
209 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500210png_charp /* PRIVATE */
211png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600212 png_charp chunkdata, png_size_t chunklength,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600213 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600214{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500215 static PNG_CONST char msg[] = "Error decoding compressed text";
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500216 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600217 png_size_t text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600218
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600219 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600220 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500221 int ret = Z_OK;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600222 png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
223 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
224 png_ptr->zstream.next_out = png_ptr->zbuf;
225 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
226
227 text_size = 0;
228 text = NULL;
229
230 while (png_ptr->zstream.avail_in)
231 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500232 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600233 if (ret != Z_OK && ret != Z_STREAM_END)
234 {
235 if (png_ptr->zstream.msg != NULL)
236 png_warning(png_ptr, png_ptr->zstream.msg);
237 else
238 png_warning(png_ptr, msg);
239 inflateReset(&png_ptr->zstream);
240 png_ptr->zstream.avail_in = 0;
241
242 if (text == NULL)
243 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500244 text_size = prefix_size + png_sizeof(msg) + 1;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500245 text = (png_charp)png_malloc_warn(png_ptr, text_size);
246 if (text == NULL)
247 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500248 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -0500249 chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500250 png_error(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500251 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500252 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600253 }
254
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500255 text[text_size - 1] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600256
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500257 /* Copy what we can of the error message into the text chunk */
258 text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500259 if (text_size > png_sizeof(msg))
260 text_size = png_sizeof(msg);
261 png_memcpy(text + prefix_size, msg, text_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600262 break;
263 }
264 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
265 {
266 if (text == NULL)
267 {
268 text_size = prefix_size +
269 png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500270 text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
271 if (text == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500272 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500273 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -0500274 chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500275 png_error(png_ptr,
276 "Not enough memory to decompress chunk");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500277 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500278 png_memcpy(text + prefix_size, png_ptr->zbuf,
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500279 text_size - prefix_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500280 png_memcpy(text, chunkdata, prefix_size);
281 *(text + text_size) = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600282 }
283 else
284 {
285 png_charp tmp;
286
287 tmp = text;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500288 text = (png_charp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500289 (png_size_t)(text_size +
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600290 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500291 if (text == NULL)
292 {
293 png_free(png_ptr, tmp);
294 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -0500295 chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500296 png_error(png_ptr,
297 "Not enough memory to decompress chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500298 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600299 png_memcpy(text, tmp, text_size);
300 png_free(png_ptr, tmp);
301 png_memcpy(text + text_size, png_ptr->zbuf,
302 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
303 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
304 *(text + text_size) = 0x00;
305 }
306 if (ret == Z_STREAM_END)
307 break;
308 else
309 {
310 png_ptr->zstream.next_out = png_ptr->zbuf;
311 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
312 }
313 }
314 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500315 if (ret != Z_STREAM_END)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500316 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500317#if !defined(PNG_NO_STDIO)
Glenn Randers-Pehrsonf46918d2006-06-02 05:31:20 -0500318 char umsg[52];
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500319
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500320 if (ret == Z_BUF_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500321 png_snprintf(umsg, 52,
322 "Buffer error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500323 png_ptr->chunk_name);
324 else if (ret == Z_DATA_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500325 png_snprintf(umsg, 52,
326 "Data error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500327 png_ptr->chunk_name);
328 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500329 png_snprintf(umsg, 52,
330 "Incomplete compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500331 png_ptr->chunk_name);
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500332 png_warning(png_ptr, umsg);
333#else
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500334 png_warning(png_ptr,
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500335 "Incomplete compressed datastream in chunk other than IDAT");
336#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500337 text_size = prefix_size;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600338 if (text == NULL)
339 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500340 text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
341 if (text == NULL)
342 {
343 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -0500344 chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500345 png_error(png_ptr, "Not enough memory for text");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500346 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500347 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600348 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500349 *(text + text_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500350 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600351
352 inflateReset(&png_ptr->zstream);
353 png_ptr->zstream.avail_in = 0;
354
355 png_free(png_ptr, chunkdata);
356 chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600357 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600358 }
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600359 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600360 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500361#if !defined(PNG_NO_STDIO)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600362 char umsg[50];
363
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500364 png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600365 png_warning(png_ptr, umsg);
366#else
367 png_warning(png_ptr, "Unknown zTXt compression type");
368#endif
369
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -0600370 *(chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500371 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600372 }
373
374 return chunkdata;
375}
376#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600377
Guy Schalnat0d580581995-07-20 02:43:20 -0500378/* read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500379void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600380png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500381{
382 png_byte buf[13];
383 png_uint_32 width, height;
384 int bit_depth, color_type, compression_type, filter_type;
385 int interlace_type;
386
Andreas Dilger47a0c421997-05-16 02:46:07 -0500387 png_debug(1, "in png_handle_IHDR\n");
388
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600389 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500390 png_error(png_ptr, "Out of place IHDR");
391
Guy Schalnat0d580581995-07-20 02:43:20 -0500392 /* check the length */
393 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600394 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500395
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600396 png_ptr->mode |= PNG_HAVE_IHDR;
397
Guy Schalnat0d580581995-07-20 02:43:20 -0500398 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600399 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500400
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500401 width = png_get_uint_31(png_ptr, buf);
402 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500403 bit_depth = buf[8];
404 color_type = buf[9];
405 compression_type = buf[10];
406 filter_type = buf[11];
407 interlace_type = buf[12];
408
Guy Schalnat0d580581995-07-20 02:43:20 -0500409 /* set internal variables */
410 png_ptr->width = width;
411 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600412 png_ptr->bit_depth = (png_byte)bit_depth;
413 png_ptr->interlaced = (png_byte)interlace_type;
414 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500415#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600416 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500417#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500418 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500419
420 /* find number of channels */
421 switch (png_ptr->color_type)
422 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500423 case PNG_COLOR_TYPE_GRAY:
424 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500425 png_ptr->channels = 1;
426 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500427 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500428 png_ptr->channels = 3;
429 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500430 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500431 png_ptr->channels = 2;
432 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500433 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500434 png_ptr->channels = 4;
435 break;
436 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600437
Guy Schalnat0d580581995-07-20 02:43:20 -0500438 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600439 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600440 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500441 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
442 png_debug1(3, "bit_depth = %d\n", png_ptr->bit_depth);
443 png_debug1(3, "channels = %d\n", png_ptr->channels);
444 png_debug1(3, "rowbytes = %lu\n", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500445 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
446 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500447}
448
449/* read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500450void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600451png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500452{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600453 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600454 int num, i;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500455#ifndef PNG_NO_POINTER_INDEXING
456 png_colorp pal_ptr;
457#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500458
Andreas Dilger47a0c421997-05-16 02:46:07 -0500459 png_debug(1, "in png_handle_PLTE\n");
460
Guy Schalnate5a37791996-06-05 15:50:50 -0500461 if (!(png_ptr->mode & PNG_HAVE_IHDR))
462 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600463 else if (png_ptr->mode & PNG_HAVE_IDAT)
464 {
465 png_warning(png_ptr, "Invalid PLTE after IDAT");
466 png_crc_finish(png_ptr, length);
467 return;
468 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500469 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600470 png_error(png_ptr, "Duplicate PLTE chunk");
471
472 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500473
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500474 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
475 {
476 png_warning(png_ptr,
477 "Ignoring PLTE chunk in grayscale PNG");
478 png_crc_finish(png_ptr, length);
479 return;
480 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500481#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
482 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
483 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600484 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500485 return;
486 }
487#endif
488
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600489 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500490 {
491 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
492 {
493 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600494 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500495 return;
496 }
497 else
498 {
499 png_error(png_ptr, "Invalid palette chunk");
500 }
501 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500502
503 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500504
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500505#ifndef PNG_NO_POINTER_INDEXING
506 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
507 {
508 png_byte buf[3];
509
510 png_crc_read(png_ptr, buf, 3);
511 pal_ptr->red = buf[0];
512 pal_ptr->green = buf[1];
513 pal_ptr->blue = buf[2];
514 }
515#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600516 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500517 {
518 png_byte buf[3];
519
520 png_crc_read(png_ptr, buf, 3);
521 /* don't depend upon png_color being any order */
522 palette[i].red = buf[0];
523 palette[i].green = buf[1];
524 palette[i].blue = buf[2];
525 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500526#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600527
528 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
529 whatever the normal CRC configuration tells us. However, if we
530 have an RGB image, the PLTE can be considered ancillary, so
531 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600532#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600533 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600534#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600535 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500536 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600537 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600538#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600539 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
540 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600541 /* If we don't want to use the data from an ancillary chunk,
542 we have two options: an error abort, or a warning and we
543 ignore the data in this chunk (which should be OK, since
544 it's considered ancillary for a RGB or RGBA image). */
545 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
546 {
547 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
548 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500549%15+% png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600550 }
551 else
552 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600553 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600554 return;
555 }
556 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500557 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600558 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
559 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600560 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600561 }
562 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600563#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500564
Andreas Dilger47a0c421997-05-16 02:46:07 -0500565 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500566
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500567#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500568 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
569 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600570 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500571 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500572 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500573 {
574 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500575 png_ptr->num_trans = (png_uint_16)num;
576 }
577 if (info_ptr->num_trans > (png_uint_16)num)
578 {
579 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
580 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500581 }
582 }
583 }
584#endif
585
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600586}
Guy Schalnate5a37791996-06-05 15:50:50 -0500587
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500588void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600589png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
590{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500591 png_debug(1, "in png_handle_IEND\n");
592
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600593 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
594 {
595 png_error(png_ptr, "No image in file");
596 }
597
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600598 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600599
600 if (length != 0)
601 {
602 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600603 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500604 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500605
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500606 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500607}
608
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500609#if defined(PNG_READ_gAMA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500610void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600611png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500612{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600613 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600614#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500615 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600616#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500617 png_byte buf[4];
618
Andreas Dilger47a0c421997-05-16 02:46:07 -0500619 png_debug(1, "in png_handle_gAMA\n");
620
Guy Schalnate5a37791996-06-05 15:50:50 -0500621 if (!(png_ptr->mode & PNG_HAVE_IHDR))
622 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600623 else if (png_ptr->mode & PNG_HAVE_IDAT)
624 {
625 png_warning(png_ptr, "Invalid gAMA after IDAT");
626 png_crc_finish(png_ptr, length);
627 return;
628 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500629 else if (png_ptr->mode & PNG_HAVE_PLTE)
630 /* Should be an error, but we can cope with it */
631 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600632
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500633 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600634#if defined(PNG_READ_sRGB_SUPPORTED)
635 && !(info_ptr->valid & PNG_INFO_sRGB)
636#endif
637 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600638 {
639 png_warning(png_ptr, "Duplicate gAMA chunk");
640 png_crc_finish(png_ptr, length);
641 return;
642 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500643
Guy Schalnat0d580581995-07-20 02:43:20 -0500644 if (length != 4)
645 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600646 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600647 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500648 return;
649 }
650
651 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652 if (png_crc_finish(png_ptr, 0))
653 return;
654
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600655 igamma = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500656 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500657 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500658 {
659 png_warning(png_ptr,
660 "Ignoring gAMA chunk with gamma=0");
661 return;
662 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500663
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600664#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600665 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500666 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600667 {
668 png_warning(png_ptr,
669 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500670#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600671 fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600672#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600673 return;
674 }
675#endif /* PNG_READ_sRGB_SUPPORTED */
676
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600677#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600678 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600679# ifdef PNG_READ_GAMMA_SUPPORTED
680 png_ptr->gamma = file_gamma;
681# endif
682 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600683#endif
684#ifdef PNG_FIXED_POINT_SUPPORTED
685 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
686#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500687}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500688#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500689
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500690#if defined(PNG_READ_sBIT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500691void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600692png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500693{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500694 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600695 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600696
Andreas Dilger47a0c421997-05-16 02:46:07 -0500697 png_debug(1, "in png_handle_sBIT\n");
698
Guy Schalnat69b14481996-01-10 02:56:49 -0600699 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500700
Guy Schalnate5a37791996-06-05 15:50:50 -0500701 if (!(png_ptr->mode & PNG_HAVE_IHDR))
702 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600703 else if (png_ptr->mode & PNG_HAVE_IDAT)
704 {
705 png_warning(png_ptr, "Invalid sBIT after IDAT");
706 png_crc_finish(png_ptr, length);
707 return;
708 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500709 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600710 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500711 /* Should be an error, but we can cope with it */
712 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600713 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500714 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600715 {
716 png_warning(png_ptr, "Duplicate sBIT chunk");
717 png_crc_finish(png_ptr, length);
718 return;
719 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500720
Guy Schalnat0d580581995-07-20 02:43:20 -0500721 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600722 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500723 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500724 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500725
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500726 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500727 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600728 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600729 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600730 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500731 }
732
Andreas Dilger47a0c421997-05-16 02:46:07 -0500733 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600734 if (png_crc_finish(png_ptr, 0))
735 return;
736
Guy Schalnat0d580581995-07-20 02:43:20 -0500737 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
738 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600739 png_ptr->sig_bit.red = buf[0];
740 png_ptr->sig_bit.green = buf[1];
741 png_ptr->sig_bit.blue = buf[2];
742 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500743 }
744 else
745 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600746 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600747 png_ptr->sig_bit.red = buf[0];
748 png_ptr->sig_bit.green = buf[0];
749 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600750 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500751 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500752 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500753}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500754#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500755
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500756#if defined(PNG_READ_cHRM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500757void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600758png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500759{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500760 png_byte buf[32];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600761#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500762 float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600763#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600764 png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600765 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500766
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600767 png_uint_32 uint_x, uint_y;
768
Andreas Dilger47a0c421997-05-16 02:46:07 -0500769 png_debug(1, "in png_handle_cHRM\n");
770
Guy Schalnate5a37791996-06-05 15:50:50 -0500771 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600772 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600773 else if (png_ptr->mode & PNG_HAVE_IDAT)
774 {
775 png_warning(png_ptr, "Invalid cHRM after IDAT");
776 png_crc_finish(png_ptr, length);
777 return;
778 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500779 else if (png_ptr->mode & PNG_HAVE_PLTE)
780 /* Should be an error, but we can cope with it */
781 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600782
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500783 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600784#if defined(PNG_READ_sRGB_SUPPORTED)
785 && !(info_ptr->valid & PNG_INFO_sRGB)
786#endif
787 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600788 {
789 png_warning(png_ptr, "Duplicate cHRM chunk");
790 png_crc_finish(png_ptr, length);
791 return;
792 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500793
Guy Schalnat0d580581995-07-20 02:43:20 -0500794 if (length != 32)
795 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600796 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600797 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600798 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500799 }
800
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500801 png_crc_read(png_ptr, buf, 32);
802 if (png_crc_finish(png_ptr, 0))
803 return;
804
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600805 uint_x = png_get_uint_32(buf);
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500806 uint_y = png_get_uint_32(buf + 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600807 if (uint_x > 80000L || uint_y > 80000L ||
808 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600809 {
810 png_warning(png_ptr, "Invalid cHRM white point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600811 return;
812 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600813 int_x_white = (png_fixed_point)uint_x;
814 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500815
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500816 uint_x = png_get_uint_32(buf + 8);
817 uint_y = png_get_uint_32(buf + 12);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600818 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600819 {
820 png_warning(png_ptr, "Invalid cHRM red point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600821 return;
822 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600823 int_x_red = (png_fixed_point)uint_x;
824 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500825
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500826 uint_x = png_get_uint_32(buf + 16);
827 uint_y = png_get_uint_32(buf + 20);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600828 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600829 {
830 png_warning(png_ptr, "Invalid cHRM green point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600831 return;
832 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600833 int_x_green = (png_fixed_point)uint_x;
834 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500835
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500836 uint_x = png_get_uint_32(buf + 24);
837 uint_y = png_get_uint_32(buf + 28);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600838 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600839 {
840 png_warning(png_ptr, "Invalid cHRM blue point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600841 return;
842 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600843 int_x_blue = (png_fixed_point)uint_x;
844 int_y_blue = (png_fixed_point)uint_y;
845
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600846#ifdef PNG_FLOATING_POINT_SUPPORTED
847 white_x = (float)int_x_white / (float)100000.0;
848 white_y = (float)int_y_white / (float)100000.0;
849 red_x = (float)int_x_red / (float)100000.0;
850 red_y = (float)int_y_red / (float)100000.0;
851 green_x = (float)int_x_green / (float)100000.0;
852 green_y = (float)int_y_green / (float)100000.0;
853 blue_x = (float)int_x_blue / (float)100000.0;
854 blue_y = (float)int_y_blue / (float)100000.0;
855#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600856
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600857#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500858 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600859 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500860 if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
861 PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
862 PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
863 PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
864 PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
865 PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
866 PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
867 PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600868 {
869 png_warning(png_ptr,
870 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500871#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600872#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500873 fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600874 white_x, white_y, red_x, red_y);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500875 fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600876 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600877#else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500878 fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600879 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500880 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600881 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600882#endif
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500883#endif /* PNG_NO_CONSOLE_IO */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600884 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600885 return;
886 }
887#endif /* PNG_READ_sRGB_SUPPORTED */
888
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600889#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500890 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600891 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600892#endif
893#ifdef PNG_FIXED_POINT_SUPPORTED
894 png_set_cHRM_fixed(png_ptr, info_ptr,
895 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
896 int_y_green, int_x_blue, int_y_blue);
897#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500898 if (png_crc_finish(png_ptr, 0))
899 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500900}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500901#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500902
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600903#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500904void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600905png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
906{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600907 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600908 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600909
910 png_debug(1, "in png_handle_sRGB\n");
911
912 if (!(png_ptr->mode & PNG_HAVE_IHDR))
913 png_error(png_ptr, "Missing IHDR before sRGB");
914 else if (png_ptr->mode & PNG_HAVE_IDAT)
915 {
916 png_warning(png_ptr, "Invalid sRGB after IDAT");
917 png_crc_finish(png_ptr, length);
918 return;
919 }
920 else if (png_ptr->mode & PNG_HAVE_PLTE)
921 /* Should be an error, but we can cope with it */
922 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600923
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500924 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600925 {
926 png_warning(png_ptr, "Duplicate sRGB chunk");
927 png_crc_finish(png_ptr, length);
928 return;
929 }
930
931 if (length != 1)
932 {
933 png_warning(png_ptr, "Incorrect sRGB chunk length");
934 png_crc_finish(png_ptr, length);
935 return;
936 }
937
938 png_crc_read(png_ptr, buf, 1);
939 if (png_crc_finish(png_ptr, 0))
940 return;
941
942 intent = buf[0];
943 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600944 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600945 {
946 png_warning(png_ptr, "Unknown sRGB intent");
947 return;
948 }
949
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600950#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600951 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600952 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500953 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600954#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500955 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600956#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600957# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500958 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600959# endif
960#endif
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500961 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600962 {
963 png_warning(png_ptr,
964 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500965#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600966# ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500967 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
968 (int)png_ptr->int_gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600969# else
970# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500971 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600972# endif
973# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600974#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600975 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600976 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600977#endif /* PNG_READ_gAMA_SUPPORTED */
978
979#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500980#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600981 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500982 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
983 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
984 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
985 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
986 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
987 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
988 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
989 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600990 {
991 png_warning(png_ptr,
992 "Ignoring incorrect cHRM value when sRGB is also present");
993 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500994#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600995#endif /* PNG_READ_cHRM_SUPPORTED */
996
997 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
998}
999#endif /* PNG_READ_sRGB_SUPPORTED */
1000
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001001#if defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001002void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001003png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1004/* Note: this does not properly handle chunks that are > 64K under DOS */
1005{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001006 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001007 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001008 png_charp profile;
1009 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001010 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001011 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001012
1013 png_debug(1, "in png_handle_iCCP\n");
1014
1015 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1016 png_error(png_ptr, "Missing IHDR before iCCP");
1017 else if (png_ptr->mode & PNG_HAVE_IDAT)
1018 {
1019 png_warning(png_ptr, "Invalid iCCP after IDAT");
1020 png_crc_finish(png_ptr, length);
1021 return;
1022 }
1023 else if (png_ptr->mode & PNG_HAVE_PLTE)
1024 /* Should be an error, but we can cope with it */
1025 png_warning(png_ptr, "Out of place iCCP chunk");
1026
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001027 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001028 {
1029 png_warning(png_ptr, "Duplicate iCCP chunk");
1030 png_crc_finish(png_ptr, length);
1031 return;
1032 }
1033
1034#ifdef PNG_MAX_MALLOC_64K
1035 if (length > (png_uint_32)65535L)
1036 {
1037 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1038 skip = length - (png_uint_32)65535L;
1039 length = (png_uint_32)65535L;
1040 }
1041#endif
1042
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001043 png_free(png_ptr, png_ptr->chunkdata);
1044 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001045 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001046 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001047
1048 if (png_crc_finish(png_ptr, skip))
1049 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001050 png_free(png_ptr, png_ptr->chunkdata);
1051 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001052 return;
1053 }
1054
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001055 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001056
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001057 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001058 /* empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001059
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001060 ++profile;
1061
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001062 /* there should be at least one zero (the compression type byte)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001063 following the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001064 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001065 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001066 png_free(png_ptr, png_ptr->chunkdata);
1067 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001068 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001069 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001070 }
1071
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001072 /* compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001073 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001074 if (compression_type)
1075 {
1076 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001077 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001078 wrote nonzero) */
1079 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001080
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001081 prefix_length = profile - png_ptr->chunkdata;
1082 png_ptr->chunkdata = png_decompress_chunk(png_ptr, compression_type,
1083 png_ptr->chunkdata, slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001084
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001085 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001086
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001087 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001088 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001089 png_free(png_ptr, png_ptr->chunkdata);
1090 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001091 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1092 return;
1093 }
1094
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001095 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001096 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001097 profile_size = ((*(pC ))<<24) |
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001098 ((*(pC + 1))<<16) |
1099 ((*(pC + 2))<< 8) |
1100 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001101
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001102 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001103 profile_length = profile_size;
1104
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001105 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001106 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001107 png_free(png_ptr, png_ptr->chunkdata);
1108 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001109 png_warning(png_ptr, "Ignoring truncated iCCP profile");
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001110 return;
1111 }
1112
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001113 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
1114 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
1115 png_free(png_ptr, png_ptr->chunkdata);
1116 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001117}
1118#endif /* PNG_READ_iCCP_SUPPORTED */
1119
1120#if defined(PNG_READ_sPLT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001121void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001122png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1123/* Note: this does not properly handle chunks that are > 64K under DOS */
1124{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001125 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001126 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001127#ifdef PNG_NO_POINTER_INDEXING
1128 png_sPLT_entryp pp;
1129#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001130 int data_length, entry_size, i;
1131 png_uint_32 skip = 0;
1132 png_size_t slength;
1133
1134 png_debug(1, "in png_handle_sPLT\n");
1135
1136 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1137 png_error(png_ptr, "Missing IHDR before sPLT");
1138 else if (png_ptr->mode & PNG_HAVE_IDAT)
1139 {
1140 png_warning(png_ptr, "Invalid sPLT after IDAT");
1141 png_crc_finish(png_ptr, length);
1142 return;
1143 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001144
1145#ifdef PNG_MAX_MALLOC_64K
1146 if (length > (png_uint_32)65535L)
1147 {
1148 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1149 skip = length - (png_uint_32)65535L;
1150 length = (png_uint_32)65535L;
1151 }
1152#endif
1153
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001154 png_free(png_ptr, png_ptr->chunkdata);
1155 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001156 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001157 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001158
1159 if (png_crc_finish(png_ptr, skip))
1160 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001161 png_free(png_ptr, png_ptr->chunkdata);
1162 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001163 return;
1164 }
1165
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001166 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001167
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001168 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; entry_start++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001169 /* empty loop to find end of name */ ;
1170 ++entry_start;
1171
1172 /* a sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001173 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001174 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001175 png_free(png_ptr, png_ptr->chunkdata);
1176 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001177 png_warning(png_ptr, "malformed sPLT chunk");
1178 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001179 }
1180
1181 new_palette.depth = *entry_start++;
1182 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001183 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001184
1185 /* integrity-check the data length */
1186 if (data_length % entry_size)
1187 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001188 png_free(png_ptr, png_ptr->chunkdata);
1189 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001190 png_warning(png_ptr, "sPLT chunk has bad length");
1191 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001192 }
1193
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001194 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001195 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001196 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001197 {
1198 png_warning(png_ptr, "sPLT chunk too long");
1199 return;
1200 }
1201 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001202 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001203 if (new_palette.entries == NULL)
1204 {
1205 png_warning(png_ptr, "sPLT chunk requires too much memory");
1206 return;
1207 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001208
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001209#ifndef PNG_NO_POINTER_INDEXING
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001210 for (i = 0; i < new_palette.nentries; i++)
1211 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001212 png_sPLT_entryp pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001213
1214 if (new_palette.depth == 8)
1215 {
1216 pp->red = *entry_start++;
1217 pp->green = *entry_start++;
1218 pp->blue = *entry_start++;
1219 pp->alpha = *entry_start++;
1220 }
1221 else
1222 {
1223 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1224 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1225 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1226 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1227 }
1228 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1229 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001230#else
1231 pp = new_palette.entries;
1232 for (i = 0; i < new_palette.nentries; i++)
1233 {
1234
1235 if (new_palette.depth == 8)
1236 {
1237 pp[i].red = *entry_start++;
1238 pp[i].green = *entry_start++;
1239 pp[i].blue = *entry_start++;
1240 pp[i].alpha = *entry_start++;
1241 }
1242 else
1243 {
1244 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1245 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1246 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1247 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1248 }
1249 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1250 }
1251#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001252
1253 /* discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001254 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001255
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001256 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001257
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001258 png_free(png_ptr, png_ptr->chunkdata);
1259 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001260 png_free(png_ptr, new_palette.entries);
1261}
1262#endif /* PNG_READ_sPLT_SUPPORTED */
1263
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001264#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001265void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001266png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001267{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001268 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001269
Andreas Dilger47a0c421997-05-16 02:46:07 -05001270 png_debug(1, "in png_handle_tRNS\n");
1271
Guy Schalnate5a37791996-06-05 15:50:50 -05001272 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1273 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001274 else if (png_ptr->mode & PNG_HAVE_IDAT)
1275 {
1276 png_warning(png_ptr, "Invalid tRNS after IDAT");
1277 png_crc_finish(png_ptr, length);
1278 return;
1279 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001280 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001281 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001282 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001283 png_crc_finish(png_ptr, length);
1284 return;
1285 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001286
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001287 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001288 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001289 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001290
1291 if (length != 2)
1292 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001293 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001294 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001295 return;
1296 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001297
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001298 png_crc_read(png_ptr, buf, 2);
1299 png_ptr->num_trans = 1;
1300 png_ptr->trans_values.gray = png_get_uint_16(buf);
1301 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001302 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1303 {
1304 png_byte buf[6];
1305
1306 if (length != 6)
1307 {
1308 png_warning(png_ptr, "Incorrect tRNS chunk length");
1309 png_crc_finish(png_ptr, length);
1310 return;
1311 }
1312 png_crc_read(png_ptr, buf, (png_size_t)length);
1313 png_ptr->num_trans = 1;
1314 png_ptr->trans_values.red = png_get_uint_16(buf);
1315 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1316 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1317 }
1318 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1319 {
1320 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1321 {
1322 /* Should be an error, but we can cope with it. */
1323 png_warning(png_ptr, "Missing PLTE before tRNS");
1324 }
1325 if (length > (png_uint_32)png_ptr->num_palette ||
1326 length > PNG_MAX_PALETTE_LENGTH)
1327 {
1328 png_warning(png_ptr, "Incorrect tRNS chunk length");
1329 png_crc_finish(png_ptr, length);
1330 return;
1331 }
1332 if (length == 0)
1333 {
1334 png_warning(png_ptr, "Zero length tRNS chunk");
1335 png_crc_finish(png_ptr, length);
1336 return;
1337 }
1338 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1339 png_ptr->num_trans = (png_uint_16)length;
1340 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001341 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001342 {
1343 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001344 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001345 return;
1346 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001347
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001348 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001349 {
1350 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001351 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001352 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001353
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001354 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -05001355 &(png_ptr->trans_values));
1356}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001357#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001358
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001359#if defined(PNG_READ_bKGD_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001360void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001361png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001362{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001363 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001364 png_byte buf[6];
1365
Andreas Dilger47a0c421997-05-16 02:46:07 -05001366 png_debug(1, "in png_handle_bKGD\n");
1367
Guy Schalnate5a37791996-06-05 15:50:50 -05001368 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1369 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001370 else if (png_ptr->mode & PNG_HAVE_IDAT)
1371 {
1372 png_warning(png_ptr, "Invalid bKGD after IDAT");
1373 png_crc_finish(png_ptr, length);
1374 return;
1375 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001376 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1377 !(png_ptr->mode & PNG_HAVE_PLTE))
1378 {
1379 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001380 png_crc_finish(png_ptr, length);
1381 return;
1382 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001383 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001384 {
1385 png_warning(png_ptr, "Duplicate bKGD chunk");
1386 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001387 return;
1388 }
1389
Guy Schalnat0d580581995-07-20 02:43:20 -05001390 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1391 truelen = 1;
1392 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1393 truelen = 6;
1394 else
1395 truelen = 2;
1396
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001397 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001398 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001399 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001400 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001401 return;
1402 }
1403
Andreas Dilger47a0c421997-05-16 02:46:07 -05001404 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001405 if (png_crc_finish(png_ptr, 0))
1406 return;
1407
Guy Schalnate5a37791996-06-05 15:50:50 -05001408 /* We convert the index value into RGB components so that we can allow
1409 * arbitrary RGB values for background when we have transparency, and
1410 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001411 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001412 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001413 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001414 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001415 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001416 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001417 if (buf[0] > info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001418 {
1419 png_warning(png_ptr, "Incorrect bKGD chunk index value");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001420 return;
1421 }
1422 png_ptr->background.red =
1423 (png_uint_16)png_ptr->palette[buf[0]].red;
1424 png_ptr->background.green =
1425 (png_uint_16)png_ptr->palette[buf[0]].green;
1426 png_ptr->background.blue =
1427 (png_uint_16)png_ptr->palette[buf[0]].blue;
1428 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001429 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001430 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001431 {
1432 png_ptr->background.red =
1433 png_ptr->background.green =
1434 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001435 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001436 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001437 else
1438 {
1439 png_ptr->background.red = png_get_uint_16(buf);
1440 png_ptr->background.green = png_get_uint_16(buf + 2);
1441 png_ptr->background.blue = png_get_uint_16(buf + 4);
1442 }
1443
Andreas Dilger47a0c421997-05-16 02:46:07 -05001444 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001445}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001446#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001447
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001448#if defined(PNG_READ_hIST_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001449void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001450png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001451{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001452 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001453 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001454
Andreas Dilger47a0c421997-05-16 02:46:07 -05001455 png_debug(1, "in png_handle_hIST\n");
1456
Guy Schalnate5a37791996-06-05 15:50:50 -05001457 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1458 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001459 else if (png_ptr->mode & PNG_HAVE_IDAT)
1460 {
1461 png_warning(png_ptr, "Invalid hIST after IDAT");
1462 png_crc_finish(png_ptr, length);
1463 return;
1464 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001465 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1466 {
1467 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001468 png_crc_finish(png_ptr, length);
1469 return;
1470 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001471 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001472 {
1473 png_warning(png_ptr, "Duplicate hIST chunk");
1474 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001475 return;
1476 }
1477
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001478 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001479 if (num != (unsigned int) png_ptr->num_palette || num >
1480 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001481 {
1482 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001483 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001484 return;
1485 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001486
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001487 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001488 {
1489 png_byte buf[2];
1490
1491 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001492 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001493 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001494
1495 if (png_crc_finish(png_ptr, 0))
1496 return;
1497
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001498 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001499}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001500#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001501
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001502#if defined(PNG_READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001503void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001504png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001505{
1506 png_byte buf[9];
1507 png_uint_32 res_x, res_y;
1508 int unit_type;
1509
Andreas Dilger47a0c421997-05-16 02:46:07 -05001510 png_debug(1, "in png_handle_pHYs\n");
1511
Guy Schalnate5a37791996-06-05 15:50:50 -05001512 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001513 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001514 else if (png_ptr->mode & PNG_HAVE_IDAT)
1515 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001516 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001517 png_crc_finish(png_ptr, length);
1518 return;
1519 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001520 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001521 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001522 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001523 png_crc_finish(png_ptr, length);
1524 return;
1525 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001526
Guy Schalnat0d580581995-07-20 02:43:20 -05001527 if (length != 9)
1528 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001529 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001530 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001531 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001532 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001533
1534 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001535 if (png_crc_finish(png_ptr, 0))
1536 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001537
1538 res_x = png_get_uint_32(buf);
1539 res_y = png_get_uint_32(buf + 4);
1540 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001541 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001542}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001543#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001544
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001545#if defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001546void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001547png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001548{
1549 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001550 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001551 int unit_type;
1552
Andreas Dilger47a0c421997-05-16 02:46:07 -05001553 png_debug(1, "in png_handle_oFFs\n");
1554
Guy Schalnate5a37791996-06-05 15:50:50 -05001555 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1556 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001557 else if (png_ptr->mode & PNG_HAVE_IDAT)
1558 {
1559 png_warning(png_ptr, "Invalid oFFs after IDAT");
1560 png_crc_finish(png_ptr, length);
1561 return;
1562 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001563 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001564 {
1565 png_warning(png_ptr, "Duplicate oFFs chunk");
1566 png_crc_finish(png_ptr, length);
1567 return;
1568 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001569
Guy Schalnat0d580581995-07-20 02:43:20 -05001570 if (length != 9)
1571 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001572 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001573 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001574 return;
1575 }
1576
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001577 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001578 if (png_crc_finish(png_ptr, 0))
1579 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001580
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001581 offset_x = png_get_int_32(buf);
1582 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001583 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001584 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1585}
1586#endif
1587
1588#if defined(PNG_READ_pCAL_SUPPORTED)
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001589/* read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001590void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001591png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1592{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001593 png_int_32 X0, X1;
1594 png_byte type, nparams;
1595 png_charp buf, units, endptr;
1596 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001597 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001598 int i;
1599
1600 png_debug(1, "in png_handle_pCAL\n");
1601
1602 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1603 png_error(png_ptr, "Missing IHDR before pCAL");
1604 else if (png_ptr->mode & PNG_HAVE_IDAT)
1605 {
1606 png_warning(png_ptr, "Invalid pCAL after IDAT");
1607 png_crc_finish(png_ptr, length);
1608 return;
1609 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001610 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001611 {
1612 png_warning(png_ptr, "Duplicate pCAL chunk");
1613 png_crc_finish(png_ptr, length);
1614 return;
1615 }
1616
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001617 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001618 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001619 png_free(png_ptr, png_ptr->chunkdata);
1620 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1621 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001622 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001623 png_warning(png_ptr, "No memory for pCAL purpose");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001624 return;
1625 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001626 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001627 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001628
1629 if (png_crc_finish(png_ptr, 0))
1630 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001631 png_free(png_ptr, png_ptr->chunkdata);
1632 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001633 return;
1634 }
1635
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001636 png_ptr->chunkdata[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001637
1638 png_debug(3, "Finding end of pCAL purpose string\n");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001639 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001640 /* empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001641
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001642 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643
1644 /* We need to have at least 12 bytes after the purpose string
1645 in order to get the parameter information. */
1646 if (endptr <= buf + 12)
1647 {
1648 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001649 png_free(png_ptr, png_ptr->chunkdata);
1650 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001651 return;
1652 }
1653
1654 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1655 X0 = png_get_int_32((png_bytep)buf+1);
1656 X1 = png_get_int_32((png_bytep)buf+5);
1657 type = buf[9];
1658 nparams = buf[10];
1659 units = buf + 11;
1660
1661 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1662 /* Check that we have the right number of parameters for known
1663 equation types. */
1664 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1665 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1666 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1667 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1668 {
1669 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001670 png_free(png_ptr, png_ptr->chunkdata);
1671 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001672 return;
1673 }
1674 else if (type >= PNG_EQUATION_LAST)
1675 {
1676 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1677 }
1678
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001679 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001680 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001681
1682 png_debug(3, "Allocating pCAL parameters array\n");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001683 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001684 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001685 if (params == NULL)
1686 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001687 png_free(png_ptr, png_ptr->chunkdata);
1688 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001689 png_warning(png_ptr, "No memory for pCAL params");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001690 return;
1691 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001692
1693 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001694 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695 {
1696 buf++; /* Skip the null string terminator from previous parameter. */
1697
1698 png_debug1(3, "Reading pCAL parameter %d\n", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001699 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001700 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001701
1702 /* Make sure we haven't run out of data yet */
1703 if (buf > endptr)
1704 {
1705 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001706 png_free(png_ptr, png_ptr->chunkdata);
1707 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001708 png_free(png_ptr, params);
1709 return;
1710 }
1711 }
1712
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001713 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001714 units, params);
1715
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001716 png_free(png_ptr, png_ptr->chunkdata);
1717 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001718 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001719}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001720#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001721
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001722#if defined(PNG_READ_sCAL_SUPPORTED)
1723/* read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001724void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001725png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1726{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001727 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001728#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001729 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001730 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001731#else
1732#ifdef PNG_FIXED_POINT_SUPPORTED
1733 png_charp swidth, sheight;
1734#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001735#endif
1736 png_size_t slength;
1737
1738 png_debug(1, "in png_handle_sCAL\n");
1739
1740 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1741 png_error(png_ptr, "Missing IHDR before sCAL");
1742 else if (png_ptr->mode & PNG_HAVE_IDAT)
1743 {
1744 png_warning(png_ptr, "Invalid sCAL after IDAT");
1745 png_crc_finish(png_ptr, length);
1746 return;
1747 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001748 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001749 {
1750 png_warning(png_ptr, "Duplicate sCAL chunk");
1751 png_crc_finish(png_ptr, length);
1752 return;
1753 }
1754
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001755 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001756 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001757 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1758 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001759 {
1760 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1761 return;
1762 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001763 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001764 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001765
1766 if (png_crc_finish(png_ptr, 0))
1767 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001768 png_free(png_ptr, png_ptr->chunkdata);
1769 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001770 return;
1771 }
1772
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001773 png_ptr->chunkdata[slength] = 0x00; /* null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001774
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001775 ep = png_ptr->chunkdata + 1; /* skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001776
1777#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001778 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001779 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001780 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001781 png_warning(png_ptr, "malformed width string in sCAL chunk");
1782 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001783 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001784#else
1785#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001786 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1787 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001788 {
1789 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1790 return;
1791 }
1792 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001793#endif
1794#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001795
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001796 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001797 /* empty loop */ ;
1798 ep++;
1799
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001800 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001801 {
1802 png_warning(png_ptr, "Truncated sCAL chunk");
1803#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1804 !defined(PNG_FLOATING_POINT_SUPPORTED)
1805 png_free(png_ptr, swidth);
1806#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001807 png_free(png_ptr, png_ptr->chunkdata);
1808 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001809 return;
1810 }
1811
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001812#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001813 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001814 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001815 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001816 png_warning(png_ptr, "malformed height string in sCAL chunk");
1817 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001818 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001819#else
1820#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001821 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001822 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001823 {
1824 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1825 return;
1826 }
1827 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001828#endif
1829#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001830
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001831 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001832#ifdef PNG_FLOATING_POINT_SUPPORTED
1833 || width <= 0. || height <= 0.
1834#endif
1835 )
1836 {
1837 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001838 png_free(png_ptr, png_ptr->chunkdata);
1839 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001840#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001841 png_free(png_ptr, swidth);
1842 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001843#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001844 return;
1845 }
1846
1847
1848#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001849 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001850#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001851#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001852 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001853#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001854#endif
1855
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001856 png_free(png_ptr, png_ptr->chunkdata);
1857 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001858#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1859 png_free(png_ptr, swidth);
1860 png_free(png_ptr, sheight);
1861#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001862}
1863#endif
1864
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001865#if defined(PNG_READ_tIME_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001866void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001867png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001868{
1869 png_byte buf[7];
1870 png_time mod_time;
1871
Andreas Dilger47a0c421997-05-16 02:46:07 -05001872 png_debug(1, "in png_handle_tIME\n");
1873
Guy Schalnate5a37791996-06-05 15:50:50 -05001874 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001875 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001876 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001877 {
1878 png_warning(png_ptr, "Duplicate tIME chunk");
1879 png_crc_finish(png_ptr, length);
1880 return;
1881 }
1882
1883 if (png_ptr->mode & PNG_HAVE_IDAT)
1884 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001885
Guy Schalnat0d580581995-07-20 02:43:20 -05001886 if (length != 7)
1887 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001888 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001889 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001890 return;
1891 }
1892
1893 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001894 if (png_crc_finish(png_ptr, 0))
1895 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001896
1897 mod_time.second = buf[6];
1898 mod_time.minute = buf[5];
1899 mod_time.hour = buf[4];
1900 mod_time.day = buf[3];
1901 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001902 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001903
Andreas Dilger47a0c421997-05-16 02:46:07 -05001904 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001905}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001906#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001907
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001908#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001909/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001910void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001911png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001912{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001913 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001914 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001915 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001916 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001917 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001918 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001919
1920 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001921
Guy Schalnate5a37791996-06-05 15:50:50 -05001922 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1923 png_error(png_ptr, "Missing IHDR before tEXt");
1924
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001925 if (png_ptr->mode & PNG_HAVE_IDAT)
1926 png_ptr->mode |= PNG_AFTER_IDAT;
1927
Andreas Dilger47a0c421997-05-16 02:46:07 -05001928#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001929 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001930 {
1931 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001932 skip = length - (png_uint_32)65535L;
1933 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001934 }
1935#endif
1936
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001937 key = (png_charp)png_malloc_warn(png_ptr, length + 1);
1938 if (key == NULL)
1939 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001940 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001941 return;
1942 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001943 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001944 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001945
1946 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001947 {
1948 png_free(png_ptr, key);
1949 return;
1950 }
1951
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001952 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001953
1954 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001955 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001956
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001957 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001958 text++;
1959
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001960 text_ptr = (png_textp)png_malloc_warn(png_ptr,
1961 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001962 if (text_ptr == NULL)
1963 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001964 png_warning(png_ptr, "Not enough memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001965 png_free(png_ptr, key);
1966 return;
1967 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001968 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1969 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001970#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001971 text_ptr->lang = NULL;
1972 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001973 text_ptr->itxt_length = 0;
1974#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001975 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001976 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001977
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001978 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001979
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -05001980 png_free(png_ptr, key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001981 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001982 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001983 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001984}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001985#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001986
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001987#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001988/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001989void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001990png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001991{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001992 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06001993 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001994 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001995 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001996 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001997
1998 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001999 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2000 png_error(png_ptr, "Missing IHDR before zTXt");
2001
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002002 if (png_ptr->mode & PNG_HAVE_IDAT)
2003 png_ptr->mode |= PNG_AFTER_IDAT;
2004
Andreas Dilger47a0c421997-05-16 02:46:07 -05002005#ifdef PNG_MAX_MALLOC_64K
2006 /* We will no doubt have problems with chunks even half this size, but
2007 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002008 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002009 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002010 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002011 png_crc_finish(png_ptr, length);
2012 return;
2013 }
2014#endif
2015
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002016 png_free(png_ptr,png_ptr->chunkdata);
2017 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2018 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002019 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002020 png_warning(png_ptr, "Out of memory processing zTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002021 return;
2022 }
2023 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002024 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002025 if (png_crc_finish(png_ptr, 0))
2026 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002027 png_free(png_ptr, png_ptr->chunkdata);
2028 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002029 return;
2030 }
2031
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002032 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002033
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002034 for (text = png_ptr->chunkdata; *text; text++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002035 /* empty loop */ ;
2036
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002037 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002038 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002039 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002040 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002041 png_free(png_ptr, png_ptr->chunkdata);
2042 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002043 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002044 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002045 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002046 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002047 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002048 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2049 {
2050 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2051 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2052 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002053 text++; /* skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002054 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002055 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002056
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002057 png_ptr->chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type,
2058 png_ptr->chunkdata, (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002059
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002060 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2061 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002062 if (text_ptr == NULL)
2063 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002064 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002065 png_free(png_ptr, png_ptr->chunkdata);
2066 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002067 return;
2068 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002069 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002070 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002071#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002072 text_ptr->lang = NULL;
2073 text_ptr->lang_key = NULL;
2074 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002075#endif
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002076 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002077 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002078
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002079 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002080
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002081 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002082 png_free(png_ptr, png_ptr->chunkdata);
2083 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002084 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002085 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002086}
2087#endif
2088
2089#if defined(PNG_READ_iTXt_SUPPORTED)
2090/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002091void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002092png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2093{
2094 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002095 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002096 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002097 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002098 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002099 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002100
2101 png_debug(1, "in png_handle_iTXt\n");
2102
2103 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2104 png_error(png_ptr, "Missing IHDR before iTXt");
2105
2106 if (png_ptr->mode & PNG_HAVE_IDAT)
2107 png_ptr->mode |= PNG_AFTER_IDAT;
2108
2109#ifdef PNG_MAX_MALLOC_64K
2110 /* We will no doubt have problems with chunks even half this size, but
2111 there is no hard and fast rule to tell us where to stop. */
2112 if (length > (png_uint_32)65535L)
2113 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002114 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002115 png_crc_finish(png_ptr, length);
2116 return;
2117 }
2118#endif
2119
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002120 png_free(png_ptr, png_ptr->chunkdata);
2121 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2122 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002123 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002124 png_warning(png_ptr, "No memory to process iTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002125 return;
2126 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002127 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002128 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002129 if (png_crc_finish(png_ptr, 0))
2130 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002131 png_free(png_ptr, png_ptr->chunkdata);
2132 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002133 return;
2134 }
2135
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002136 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002137
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002138 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002139 /* empty loop */ ;
2140 lang++; /* skip NUL separator */
2141
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002142 /* iTXt must have a language tag (possibly empty), two compression bytes,
2143 translated keyword (possibly empty), and possibly some text after the
2144 keyword */
2145
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002146 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002147 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002148 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002149 png_free(png_ptr, png_ptr->chunkdata);
2150 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002151 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002152 }
2153 else
2154 {
2155 comp_flag = *lang++;
2156 comp_type = *lang++;
2157 }
2158
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002159 for (lang_key = lang; *lang_key; lang_key++)
2160 /* empty loop */ ;
2161 lang_key++; /* skip NUL separator */
2162
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002163 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002164 {
2165 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002166 png_free(png_ptr, png_ptr->chunkdata);
2167 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002168 return;
2169 }
2170
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002171 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002172 /* empty loop */ ;
2173 text++; /* skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002174 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002175 {
2176 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002177 png_free(png_ptr, png_ptr->chunkdata);
2178 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002179 return;
2180 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002181
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002182 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002183
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002184 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002185 if (comp_flag)
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002186 png_ptr->chunkdata = png_decompress_chunk(png_ptr, comp_type,
2187 png_ptr->chunkdata, (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002188 else
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002189 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002190 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2191 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002192 if (text_ptr == NULL)
2193 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002194 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002195 png_free(png_ptr, png_ptr->chunkdata);
2196 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002197 return;
2198 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002199 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002200 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2201 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002202 text_ptr->itxt_length = data_len;
2203 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002204 text_ptr->key = png_ptr->chunkdata;
2205 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002206
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002207 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002208
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002209 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002210 png_free(png_ptr, png_ptr->chunkdata);
2211 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002212 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002213 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002214}
2215#endif
2216
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002217/* This function is called when we haven't found a handler for a
2218 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002219 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2220 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2221 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002222void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002223png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2224{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002225 png_uint_32 skip = 0;
2226
Andreas Dilger47a0c421997-05-16 02:46:07 -05002227 png_debug(1, "in png_handle_unknown\n");
2228
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002229 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002230 {
2231#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002232 PNG_CONST PNG_IDAT;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002233#endif
2234 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
2235 png_ptr->mode |= PNG_AFTER_IDAT;
2236 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002237
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002238 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
2239
2240 if (!(png_ptr->chunk_name[0] & 0x20))
2241 {
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002242#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002243 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002244 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002245#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002246 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002247#endif
2248 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002249#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002250 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002251 }
2252
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002253#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06002254 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) ||
2255 (png_ptr->read_user_chunk_fn != NULL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002256 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002257#ifdef PNG_MAX_MALLOC_64K
2258 if (length > (png_uint_32)65535L)
2259 {
2260 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2261 skip = length - (png_uint_32)65535L;
2262 length = (png_uint_32)65535L;
2263 }
2264#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002265 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2266 (png_charp)png_ptr->chunk_name,
2267 png_sizeof(png_ptr->unknown_chunk.name));
2268 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] = '\0';
2269 png_ptr->unknown_chunk.size = (png_size_t)length;
2270 if (length == 0)
2271 png_ptr->unknown_chunk.data = NULL;
2272 else
2273 {
2274 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2275 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
2276 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002277#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002278 if (png_ptr->read_user_chunk_fn != NULL)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002279 {
2280 /* callback to user unknown chunk handler */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002281 int ret;
2282 ret = (*(png_ptr->read_user_chunk_fn))
2283 (png_ptr, &png_ptr->unknown_chunk);
2284 if (ret < 0)
2285 png_chunk_error(png_ptr, "error in user chunk");
2286 if (ret == 0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002287 {
2288 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002289 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002290 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002291 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002292 png_set_unknown_chunks(png_ptr, info_ptr,
2293 &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002294 }
2295 }
2296 else
2297#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002298 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2299 png_free(png_ptr, png_ptr->unknown_chunk.data);
2300 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002301 }
2302 else
2303#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002304 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002305
2306 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002307
2308#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002309 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002310#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002311}
2312
2313/* This function is called to verify that a chunk name is valid.
2314 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002315 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002316 functions to handle unknown critical chunks after we check that
2317 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002318
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002319#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002320
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002321void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002322png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2323{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002324 png_debug(1, "in png_check_chunk_name\n");
2325 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
2326 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002327 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002328 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002329 }
2330}
2331
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002332/* Combines the row recently read in with the existing pixels in the
2333 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002334 This routine also handles the two methods of progressive display
2335 of interlaced images, depending on the mask value.
2336 The mask value describes which pixels are to be combined with
2337 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002338 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002339 a zero indicates the pixel is to be skipped. This is in addition
2340 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002341 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002342
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002343void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002344png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002345{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002346 png_debug(1, "in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002347 if (mask == 0xff)
2348 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002349 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002350 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002351 }
2352 else
2353 {
2354 switch (png_ptr->row_info.pixel_depth)
2355 {
2356 case 1:
2357 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002358 png_bytep sp = png_ptr->row_buf + 1;
2359 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002360 int s_inc, s_start, s_end;
2361 int m = 0x80;
2362 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002363 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002364 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002365
Andreas Dilger47a0c421997-05-16 02:46:07 -05002366#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2367 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002368 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002369 s_start = 0;
2370 s_end = 7;
2371 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002372 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002373 else
2374#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002375 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002376 s_start = 7;
2377 s_end = 0;
2378 s_inc = -1;
2379 }
2380
2381 shift = s_start;
2382
2383 for (i = 0; i < row_width; i++)
2384 {
2385 if (m & mask)
2386 {
2387 int value;
2388
2389 value = (*sp >> shift) & 0x01;
2390 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2391 *dp |= (png_byte)(value << shift);
2392 }
2393
2394 if (shift == s_end)
2395 {
2396 shift = s_start;
2397 sp++;
2398 dp++;
2399 }
2400 else
2401 shift += s_inc;
2402
2403 if (m == 1)
2404 m = 0x80;
2405 else
2406 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002407 }
2408 break;
2409 }
2410 case 2:
2411 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002412 png_bytep sp = png_ptr->row_buf + 1;
2413 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002414 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002415 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002416 int shift;
2417 png_uint_32 i;
2418 png_uint_32 row_width = png_ptr->width;
2419 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002420
Andreas Dilger47a0c421997-05-16 02:46:07 -05002421#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2422 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002423 {
2424 s_start = 0;
2425 s_end = 6;
2426 s_inc = 2;
2427 }
2428 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002429#endif
2430 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002431 s_start = 6;
2432 s_end = 0;
2433 s_inc = -2;
2434 }
2435
2436 shift = s_start;
2437
2438 for (i = 0; i < row_width; i++)
2439 {
2440 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002441 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002442 value = (*sp >> shift) & 0x03;
2443 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2444 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002445 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002446
2447 if (shift == s_end)
2448 {
2449 shift = s_start;
2450 sp++;
2451 dp++;
2452 }
2453 else
2454 shift += s_inc;
2455 if (m == 1)
2456 m = 0x80;
2457 else
2458 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002459 }
2460 break;
2461 }
2462 case 4:
2463 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002464 png_bytep sp = png_ptr->row_buf + 1;
2465 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002466 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002467 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002468 int shift;
2469 png_uint_32 i;
2470 png_uint_32 row_width = png_ptr->width;
2471 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002472
Andreas Dilger47a0c421997-05-16 02:46:07 -05002473#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2474 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002475 {
2476 s_start = 0;
2477 s_end = 4;
2478 s_inc = 4;
2479 }
2480 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002481#endif
2482 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002483 s_start = 4;
2484 s_end = 0;
2485 s_inc = -4;
2486 }
2487 shift = s_start;
2488
2489 for (i = 0; i < row_width; i++)
2490 {
2491 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002492 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002493 value = (*sp >> shift) & 0xf;
2494 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2495 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002496 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002497
2498 if (shift == s_end)
2499 {
2500 shift = s_start;
2501 sp++;
2502 dp++;
2503 }
2504 else
2505 shift += s_inc;
2506 if (m == 1)
2507 m = 0x80;
2508 else
2509 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002510 }
2511 break;
2512 }
2513 default:
2514 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002515 png_bytep sp = png_ptr->row_buf + 1;
2516 png_bytep dp = row;
2517 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2518 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002519 png_uint_32 row_width = png_ptr->width;
2520 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002521
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002522
2523 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002524 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002525 if (m & mask)
2526 {
2527 png_memcpy(dp, sp, pixel_bytes);
2528 }
2529
2530 sp += pixel_bytes;
2531 dp += pixel_bytes;
2532
2533 if (m == 1)
2534 m = 0x80;
2535 else
2536 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002537 }
2538 break;
2539 }
2540 }
2541 }
2542}
2543
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002544#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002545/* OLD pre-1.0.9 interface:
2546void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2547 png_uint_32 transformations)
2548 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002549void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002550png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002551{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002552 png_row_infop row_info = &(png_ptr->row_info);
2553 png_bytep row = png_ptr->row_buf + 1;
2554 int pass = png_ptr->pass;
2555 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002556#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002557 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002558 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002559 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002560#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002561
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002562 png_debug(1, "in png_do_read_interlace\n");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002563 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002564 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002565 png_uint_32 final_width;
2566
2567 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002568
2569 switch (row_info->pixel_depth)
2570 {
2571 case 1:
2572 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002573 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2574 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002575 int sshift, dshift;
2576 int s_start, s_end, s_inc;
2577 int jstop = png_pass_inc[pass];
2578 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002579 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002580 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002581
Andreas Dilger47a0c421997-05-16 02:46:07 -05002582#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2583 if (transformations & PNG_PACKSWAP)
2584 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002585 sshift = (int)((row_info->width + 7) & 0x07);
2586 dshift = (int)((final_width + 7) & 0x07);
2587 s_start = 7;
2588 s_end = 0;
2589 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002590 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002591 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002592#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002593 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002594 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2595 dshift = 7 - (int)((final_width + 7) & 0x07);
2596 s_start = 0;
2597 s_end = 7;
2598 s_inc = 1;
2599 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002600
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002601 for (i = 0; i < row_info->width; i++)
2602 {
2603 v = (png_byte)((*sp >> sshift) & 0x01);
2604 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002605 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002606 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2607 *dp |= (png_byte)(v << dshift);
2608 if (dshift == s_end)
2609 {
2610 dshift = s_start;
2611 dp--;
2612 }
2613 else
2614 dshift += s_inc;
2615 }
2616 if (sshift == s_end)
2617 {
2618 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002619 sp--;
2620 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002621 else
2622 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002623 }
2624 break;
2625 }
2626 case 2:
2627 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002628 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2629 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2630 int sshift, dshift;
2631 int s_start, s_end, s_inc;
2632 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002633 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002634
Andreas Dilger47a0c421997-05-16 02:46:07 -05002635#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2636 if (transformations & PNG_PACKSWAP)
2637 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002638 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2639 dshift = (int)(((final_width + 3) & 0x03) << 1);
2640 s_start = 6;
2641 s_end = 0;
2642 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002643 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002644 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002645#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002646 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002647 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2648 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2649 s_start = 0;
2650 s_end = 6;
2651 s_inc = 2;
2652 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002653
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002654 for (i = 0; i < row_info->width; i++)
2655 {
2656 png_byte v;
2657 int j;
2658
2659 v = (png_byte)((*sp >> sshift) & 0x03);
2660 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002661 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002662 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2663 *dp |= (png_byte)(v << dshift);
2664 if (dshift == s_end)
2665 {
2666 dshift = s_start;
2667 dp--;
2668 }
2669 else
2670 dshift += s_inc;
2671 }
2672 if (sshift == s_end)
2673 {
2674 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002675 sp--;
2676 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002677 else
2678 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002679 }
2680 break;
2681 }
2682 case 4:
2683 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002684 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2685 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002686 int sshift, dshift;
2687 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002688 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002689 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002690
Andreas Dilger47a0c421997-05-16 02:46:07 -05002691#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2692 if (transformations & PNG_PACKSWAP)
2693 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002694 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2695 dshift = (int)(((final_width + 1) & 0x01) << 2);
2696 s_start = 4;
2697 s_end = 0;
2698 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002699 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002700 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002701#endif
2702 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002703 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2704 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2705 s_start = 0;
2706 s_end = 4;
2707 s_inc = 4;
2708 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002709
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002710 for (i = 0; i < row_info->width; i++)
2711 {
2712 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2713 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002714
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002715 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002716 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002717 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2718 *dp |= (png_byte)(v << dshift);
2719 if (dshift == s_end)
2720 {
2721 dshift = s_start;
2722 dp--;
2723 }
2724 else
2725 dshift += s_inc;
2726 }
2727 if (sshift == s_end)
2728 {
2729 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002730 sp--;
2731 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002732 else
2733 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002734 }
2735 break;
2736 }
2737 default:
2738 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002739 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
2740 png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002741 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002742
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002743 int jstop = png_pass_inc[pass];
2744 png_uint_32 i;
2745
2746 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002747 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002748 png_byte v[8];
2749 int j;
2750
2751 png_memcpy(v, sp, pixel_bytes);
2752 for (j = 0; j < jstop; j++)
2753 {
2754 png_memcpy(dp, v, pixel_bytes);
2755 dp -= pixel_bytes;
2756 }
2757 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002758 }
2759 break;
2760 }
2761 }
2762 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002763 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002764 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002765#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002766 transformations = transformations; /* silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002767#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002768}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002769#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002770
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002771void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002772png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002773 png_bytep prev_row, int filter)
2774{
2775 png_debug(1, "in png_read_filter_row\n");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002776 png_debug2(2, "row = %lu, filter = %d\n", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002777 switch (filter)
2778 {
2779 case PNG_FILTER_VALUE_NONE:
2780 break;
2781 case PNG_FILTER_VALUE_SUB:
2782 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002783 png_uint_32 i;
2784 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002785 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002786 png_bytep rp = row + bpp;
2787 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002788
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002789 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002790 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002791 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2792 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002793 }
2794 break;
2795 }
2796 case PNG_FILTER_VALUE_UP:
2797 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002798 png_uint_32 i;
2799 png_uint_32 istop = row_info->rowbytes;
2800 png_bytep rp = row;
2801 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002802
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002803 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002804 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002805 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2806 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002807 }
2808 break;
2809 }
2810 case PNG_FILTER_VALUE_AVG:
2811 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002812 png_uint_32 i;
2813 png_bytep rp = row;
2814 png_bytep pp = prev_row;
2815 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002816 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002817 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002818
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002819 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002820 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002821 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002822 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002823 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002824 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002825
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002826 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002827 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002828 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002829 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002830 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002831 }
2832 break;
2833 }
2834 case PNG_FILTER_VALUE_PAETH:
2835 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002836 png_uint_32 i;
2837 png_bytep rp = row;
2838 png_bytep pp = prev_row;
2839 png_bytep lp = row;
2840 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002841 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002842 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002843
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002844 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002845 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002846 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2847 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002848 }
2849
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002850 for (i = 0; i < istop; i++) /* use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002851 {
2852 int a, b, c, pa, pb, pc, p;
2853
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002854 a = *lp++;
2855 b = *pp++;
2856 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002857
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002858 p = b - c;
2859 pc = a - c;
2860
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002861#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002862 pa = abs(p);
2863 pb = abs(pc);
2864 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002865#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002866 pa = p < 0 ? -p : p;
2867 pb = pc < 0 ? -pc : pc;
2868 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002869#endif
2870
2871 /*
2872 if (pa <= pb && pa <= pc)
2873 p = a;
2874 else if (pb <= pc)
2875 p = b;
2876 else
2877 p = c;
2878 */
2879
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002880 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002881
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002882 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2883 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002884 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002885 break;
2886 }
2887 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002888 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002889 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002890 break;
2891 }
2892}
Guy Schalnat0d580581995-07-20 02:43:20 -05002893
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002894void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002895png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002896{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002897#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002898#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002899 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002900
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002901 /* start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002902 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002903
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002904 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002905 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002906
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002907 /* start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002908 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002909
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002910 /* offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002911 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
2912#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002913#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002914
Andreas Dilger47a0c421997-05-16 02:46:07 -05002915 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002916 png_ptr->row_number++;
2917 if (png_ptr->row_number < png_ptr->num_rows)
2918 return;
2919
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002920#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05002921 if (png_ptr->interlaced)
2922 {
2923 png_ptr->row_number = 0;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002924 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002925 do
2926 {
2927 png_ptr->pass++;
2928 if (png_ptr->pass >= 7)
2929 break;
2930 png_ptr->iwidth = (png_ptr->width +
2931 png_pass_inc[png_ptr->pass] - 1 -
2932 png_pass_start[png_ptr->pass]) /
2933 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002934
2935 png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
2936 png_ptr->iwidth) + 1;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002937
Guy Schalnat0d580581995-07-20 02:43:20 -05002938 if (!(png_ptr->transformations & PNG_INTERLACE))
2939 {
2940 png_ptr->num_rows = (png_ptr->height +
2941 png_pass_yinc[png_ptr->pass] - 1 -
2942 png_pass_ystart[png_ptr->pass]) /
2943 png_pass_yinc[png_ptr->pass];
2944 if (!(png_ptr->num_rows))
2945 continue;
2946 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002947 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002948 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 } while (png_ptr->iwidth == 0);
2950
2951 if (png_ptr->pass < 7)
2952 return;
2953 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002954#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002955
Guy Schalnate5a37791996-06-05 15:50:50 -05002956 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002957 {
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002958#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002959 PNG_CONST PNG_IDAT;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002960#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002961 char extra;
2962 int ret;
2963
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002964 png_ptr->zstream.next_out = (Byte *)&extra;
2965 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002966 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05002967 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002968 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002969 {
2970 while (!png_ptr->idat_size)
2971 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002972 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002973
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002974 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002975
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002976 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05002977 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05002978 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002979 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002980 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002981 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002982
2983 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002984 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2985 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002986 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002987 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2988 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2989 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002990 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002991 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002992 if (ret == Z_STREAM_END)
2993 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002994 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002995 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05002996 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002997 png_ptr->mode |= PNG_AFTER_IDAT;
2998 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002999 break;
3000 }
3001 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003002 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05003003 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003004
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003005 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003006 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003007 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003008 png_ptr->mode |= PNG_AFTER_IDAT;
3009 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3010 break;
3011 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003012
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003013 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003014 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003015 }
3016
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003017 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003018 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003019
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003020 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003021
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003022 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003023}
3024
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003025void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003026png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003027{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003028#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003029#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003030 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003031
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003032 /* start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003033 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003034
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003035 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003036 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003037
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003038 /* start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003039 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003040
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003041 /* offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003042 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3043#endif
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003044#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003045
Guy Schalnat0d580581995-07-20 02:43:20 -05003046 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003047 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003048
Andreas Dilger47a0c421997-05-16 02:46:07 -05003049 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003050 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003051 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003052#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003053 if (png_ptr->interlaced)
3054 {
3055 if (!(png_ptr->transformations & PNG_INTERLACE))
3056 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
3057 png_pass_ystart[0]) / png_pass_yinc[0];
3058 else
3059 png_ptr->num_rows = png_ptr->height;
3060
3061 png_ptr->iwidth = (png_ptr->width +
3062 png_pass_inc[png_ptr->pass] - 1 -
3063 png_pass_start[png_ptr->pass]) /
3064 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003065
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003066 png_ptr->irowbytes =
3067 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003068 }
3069 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003070#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003071 {
3072 png_ptr->num_rows = png_ptr->height;
3073 png_ptr->iwidth = png_ptr->width;
3074 png_ptr->irowbytes = png_ptr->rowbytes + 1;
3075 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003076 max_pixel_depth = png_ptr->pixel_depth;
3077
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003078#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003079 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003080 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003081#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003082
Guy Schalnate5a37791996-06-05 15:50:50 -05003083#if defined(PNG_READ_EXPAND_SUPPORTED)
3084 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003085 {
3086 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3087 {
3088 if (png_ptr->num_trans)
3089 max_pixel_depth = 32;
3090 else
3091 max_pixel_depth = 24;
3092 }
3093 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3094 {
3095 if (max_pixel_depth < 8)
3096 max_pixel_depth = 8;
3097 if (png_ptr->num_trans)
3098 max_pixel_depth *= 2;
3099 }
3100 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3101 {
3102 if (png_ptr->num_trans)
3103 {
3104 max_pixel_depth *= 4;
3105 max_pixel_depth /= 3;
3106 }
3107 }
3108 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003109#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003110
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003111#if defined(PNG_READ_FILLER_SUPPORTED)
3112 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003113 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003114 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3115 max_pixel_depth = 32;
3116 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003117 {
3118 if (max_pixel_depth <= 8)
3119 max_pixel_depth = 16;
3120 else
3121 max_pixel_depth = 32;
3122 }
3123 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3124 {
3125 if (max_pixel_depth <= 32)
3126 max_pixel_depth = 32;
3127 else
3128 max_pixel_depth = 64;
3129 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003130 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003131#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003132
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003133#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003134 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3135 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003136 if (
3137#if defined(PNG_READ_EXPAND_SUPPORTED)
3138 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
3139#endif
3140#if defined(PNG_READ_FILLER_SUPPORTED)
3141 (png_ptr->transformations & (PNG_FILLER)) ||
3142#endif
3143 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003144 {
3145 if (max_pixel_depth <= 16)
3146 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003147 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003148 max_pixel_depth = 64;
3149 }
3150 else
3151 {
3152 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003153 {
3154 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3155 max_pixel_depth = 32;
3156 else
3157 max_pixel_depth = 24;
3158 }
3159 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3160 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003161 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003162 max_pixel_depth = 48;
3163 }
3164 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003165#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003166
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003167#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3168defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003169 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003170 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003171 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003172 png_ptr->user_transform_channels;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003173 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003174 max_pixel_depth=user_pixel_depth;
3175 }
3176#endif
3177
Guy Schalnat0d580581995-07-20 02:43:20 -05003178 /* align the width on the next larger 8 pixels. Mainly used
3179 for interlacing */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003180 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Guy Schalnat0d580581995-07-20 02:43:20 -05003181 /* calculate the maximum bytes needed, adding a byte and a pixel
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003182 for safety's sake */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003183 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 1 + ((max_pixel_depth + 7) >> 3);
3185#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003186 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003187 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003188#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003189
3190 if (row_bytes + 64 > png_ptr->old_big_row_buf_size)
3191 {
3192 png_free(png_ptr, png_ptr->big_row_buf);
3193 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
3194 png_ptr->row_buf = png_ptr->big_row_buf+32;
3195 png_ptr->old_big_row_buf_size = row_bytes+64;
3196 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003197
3198#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003199 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003200 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003201#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003202 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003203 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003204
3205 if (png_ptr->rowbytes+1 > png_ptr->old_prev_row_size)
3206 {
3207 png_free(png_ptr, png_ptr->prev_row);
3208 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
3209 png_ptr->rowbytes + 1));
3210 png_ptr->old_prev_row_size = png_ptr->rowbytes+1;
3211 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003212
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003213 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003214
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003215 png_debug1(3, "width = %lu,\n", png_ptr->width);
3216 png_debug1(3, "height = %lu,\n", png_ptr->height);
3217 png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
3218 png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
3219 png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
3220 png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05003221
Guy Schalnate5a37791996-06-05 15:50:50 -05003222 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003223}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003224#endif /* PNG_READ_SUPPORTED */