blob: de4ac7a57884da50c4effa5548bb6df8a5d49eb7 [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-Pehrsonbcb3aac2010-09-10 22:05:27 -05004 * Last changed in libpng 1.4.1 [September 11, 2010]
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06005 * Copyright (c) 1998-2010 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrson3e61d792009-06-24 09:31:28 -050012 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050013 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060014 * libpng itself during the course of reading an image.
15 */
Guy Schalnat0d580581995-07-20 02:43:20 -050016
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050017#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050018
Glenn Randers-Pehrsonc3cd22b2010-03-08 21:10:25 -060019#ifdef PNG_READ_SUPPORTED
20
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050021# define png_strtod(p,a,b) strtod(a,b)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060022png_uint_32 PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050023png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050024{
25 png_uint_32 i = png_get_uint_32(buf);
26 if (i > PNG_UINT_31_MAX)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060027 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050028 return (i);
29}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050030
31#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
32/* The following is a variation on the above for use with the fixed
33 * point values used for gAMA and cHRM. Instead of png_error it
34 * issues a warning and returns (-1) - an invalid value because both
35 * gAMA and cHRM use *unsigned* integers for fixed point values.
36 */
37#define PNG_FIXED_ERROR (-1)
38
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050039static png_fixed_point /* PRIVATE */
40png_get_fixed_point(png_structp png_ptr, png_const_bytep buf)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050041{
42 png_uint_32 u = png_get_uint_32(buf);
43 if (u <= PNG_UINT_31_MAX)
44 return (png_fixed_point)u; /* known to be in range */
45
46 /* The caller can turn off the warning by passing NULL. */
47 if (png_ptr != NULL)
48 png_warning(png_ptr, "PNG fixed point integer out of range");
49 return PNG_FIXED_ERROR;
50}
51#endif
52
Glenn Randers-Pehrson34713ce2010-04-28 07:49:28 -050053#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
54/* NOTE: the read macros will obscure these definitions, so that if
55 * PNG_USE_READ_MACROS is set the library will not use them internally,
56 * but the APIs will still be available externally.
57 */
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050058/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050059png_uint_32 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050060png_get_uint_32)(png_const_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050061{
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060062 png_uint_32 i =
63 ((png_uint_32)(*(buf )) << 24) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060064 ((png_uint_32)(*(buf + 1)) << 16) +
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060065 ((png_uint_32)(*(buf + 2)) << 8) +
66 ((png_uint_32)(*(buf + 3)) ) ;
Guy Schalnat0d580581995-07-20 02:43:20 -050067
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060068 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050069}
70
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050071/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050072 * data is stored in the PNG file in two's complement format and there
73 * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -050074 * the following code does a two's complement to native conversion.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050075 */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050076png_int_32 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050077png_get_int_32)(png_const_bytep buf)
Andreas Dilger47a0c421997-05-16 02:46:07 -050078{
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050079 png_uint_32 u = png_get_uint_32(buf);
Glenn Randers-Pehrson53c75022010-07-30 09:58:34 -050080 if ((u & 0x80000000) == 0) /* non-negative */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050081 return u;
Andreas Dilger47a0c421997-05-16 02:46:07 -050082
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050083 u = (u ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
Glenn Randers-Pehrson53c75022010-07-30 09:58:34 -050084 return -(png_int_32)u;
Andreas Dilger47a0c421997-05-16 02:46:07 -050085}
Andreas Dilger47a0c421997-05-16 02:46:07 -050086
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050087/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050088png_uint_16 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050089png_get_uint_16)(png_const_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050090{
Glenn Randers-Pehrson48dc6eb2010-07-31 07:09:58 -050091 png_uint_16 i =
92 ((png_uint_32)(*buf) << 8) +
93 ((png_uint_32)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050094
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060095 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050096}
Glenn Randers-Pehrson34713ce2010-04-28 07:49:28 -050097#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050098
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050099/* Read the chunk header (length + type name).
100 * Put the type name into png_ptr->chunk_name, and return the length.
101 */
102png_uint_32 /* PRIVATE */
103png_read_chunk_header(png_structp png_ptr)
104{
105 png_byte buf[8];
106 png_uint_32 length;
107
108#ifdef PNG_IO_STATE_SUPPORTED
109 /* Inform the I/O callback that the chunk header is being read.
110 * PNG_IO_CHUNK_HDR requires a single I/O call.
111 */
112 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
113#endif
114
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500115 /* Read the length and the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500116 png_read_data(png_ptr, buf, 8);
117 length = png_get_uint_31(png_ptr, buf);
118
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500119 /* Put the chunk name into png_ptr->chunk_name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500120 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
121
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -0600122 png_debug2(0, "Reading %s chunk, length = %u",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600123 png_ptr->chunk_name, length);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500124
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500125 /* Reset the crc and run it over the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500126 png_reset_crc(png_ptr);
127 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
128
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500129 /* Check to see if chunk name is valid */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500130 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
131
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500132#ifdef PNG_IO_STATE_SUPPORTED
133 /* Inform the I/O callback that chunk data will (possibly) be read.
134 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
135 */
136 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
137#endif
138
139 return length;
140}
141
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500142/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500143void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500144png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500145{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500146 if (png_ptr == NULL)
147 return;
Guy Schalnat6d764711995-12-19 03:22:19 -0600148 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500149 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500150}
151
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600152/* Optionally skip data and then check the CRC. Depending on whether we
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500153 * are reading a ancillary or critical chunk, and how the program has set
154 * things up, we may calculate the CRC on the data and print a message.
155 * Returns '1' if there was a CRC error, '0' otherwise.
156 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500157int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600158png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500159{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500160 png_size_t i;
161 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500162
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500163 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600164 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500165 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500166 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500167
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500168 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500169 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500170 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500171 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600172
Andreas Dilger47a0c421997-05-16 02:46:07 -0500173 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600174 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500175 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500176 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500177 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600178 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600179 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600180 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600181 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500182
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600183 else
184 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500185 png_chunk_benign_error(png_ptr, "CRC error");
186 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600187 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500188
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600189 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600190 }
191
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600192 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500193}
194
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600195/* Compare the CRC stored in the PNG file with that calculated by libpng from
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500196 * the data it has read thus far.
197 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500198int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600199png_crc_error(png_structp png_ptr)
200{
201 png_byte crc_bytes[4];
202 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500203 int need_crc = 1;
204
205 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
206 {
207 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
208 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
209 need_crc = 0;
210 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500211
Andreas Dilger47a0c421997-05-16 02:46:07 -0500212 else /* critical */
213 {
214 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
215 need_crc = 0;
216 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600217
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500218#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500219 /* Inform the I/O callback that the chunk CRC is being read */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500220 /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */
221 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
222#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500223
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600224 png_read_data(png_ptr, crc_bytes, 4);
225
Andreas Dilger47a0c421997-05-16 02:46:07 -0500226 if (need_crc)
227 {
228 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600229 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500230 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500231
Andreas Dilger47a0c421997-05-16 02:46:07 -0500232 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600233 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600234}
235
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600236#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500237 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600238static png_size_t
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500239png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600240 png_bytep output, png_size_t output_size)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600241{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600242 png_size_t count = 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600243
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500244 /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
245 * even necessarily handle 65536 bytes) because the type uInt is "16 bits or
246 * more". Consequently it is necessary to chunk the input to zlib. This
247 * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value
248 * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a
249 * lower value in pngpriv.h and this may sometimes have a performance
250 * advantage, because it forces access of the input data to be separated from
251 * at least some of the use by some period of time.
252 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500253 png_ptr->zstream.next_in = data;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500254 /* avail_in is set below from 'size' */
255 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600256
257 while (1)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600258 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600259 int ret, avail;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600260
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500261 /* The setting of 'avail_in' used to be outside the loop, by setting it
262 * inside it is possible to chunk the input to zlib and simply rely on
263 * zlib to advance the 'next_in' pointer. This allows arbitrary amounts o
264 * data to be passed through zlib at the unavoidable cost of requiring a
265 * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX
266 * input bytes.
267 */
268 if (png_ptr->zstream.avail_in == 0 && size > 0)
269 {
270 if (size <= ZLIB_IO_MAX)
271 {
272 /* The value is less than ZLIB_IO_MAX so the cast is safe: */
273 png_ptr->zstream.avail_in = (uInt)size;
274 size = 0;
275 }
276
277 else
278 {
279 png_ptr->zstream.avail_in = ZLIB_IO_MAX;
280 size -= ZLIB_IO_MAX;
281 }
282 }
283
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600284 /* Reset the output buffer each time round - we empty it
285 * after every inflate call.
286 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600287 png_ptr->zstream.next_out = png_ptr->zbuf;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600288 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600289
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600290 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
291 avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600292
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600293 /* First copy/count any new output - but only if we didn't
294 * get an error code.
295 */
296 if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600297 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500298 png_size_t space = avail; /* > 0, see above */
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600299 if (output != 0 && output_size > count)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600300 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500301 png_size_t copy = output_size - count;
302 if (space < copy)
303 copy = space;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600304 png_memcpy(output + count, png_ptr->zbuf, copy);
305 }
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500306 count += space;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600307 }
308
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600309 if (ret == Z_OK)
310 continue;
311
312 /* Termination conditions - always reset the zstream, it
313 * must be left in inflateInit state.
314 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600315 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600316 inflateReset(&png_ptr->zstream);
317
318 if (ret == Z_STREAM_END)
319 return count; /* NOTE: may be zero. */
320
321 /* Now handle the error codes - the API always returns 0
322 * and the error message is dumped into the uncompressed
323 * buffer if available.
324 */
325 {
Glenn Randers-Pehrson6cac43c2010-06-26 12:33:17 -0500326 PNG_CONST char *msg;
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600327#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrsond9d4cec2010-07-12 07:12:09 -0500328 char umsg[52];
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600329#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600330 if (png_ptr->zstream.msg != 0)
331 msg = png_ptr->zstream.msg;
332 else
333 {
Glenn Randers-Pehrson6a9e4802010-02-19 09:47:43 -0600334#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600335 switch (ret)
336 {
337 case Z_BUF_ERROR:
338 msg = "Buffer error in compressed datastream in %s chunk";
339 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500340
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600341 case Z_DATA_ERROR:
342 msg = "Data error in compressed datastream in %s chunk";
343 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500344
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600345 default:
346 msg = "Incomplete compressed datastream in %s chunk";
347 break;
348 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600349
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600350 png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
351 msg = umsg;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600352#else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600353 msg = "Damaged compressed datastream in chunk other than IDAT";
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600354#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600355 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600356
357 png_warning(png_ptr, msg);
358 }
359
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600360 /* 0 means an error - notice that this code simply ignores
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600361 * zero length compressed chunks as a result.
362 */
363 return 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600364 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600365}
366
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600367/*
368 * Decompress trailing data in a chunk. The assumption is that chunkdata
369 * points at an allocated area holding the contents of a chunk with a
370 * trailing compressed part. What we get back is an allocated area
371 * holding the original prefix part and an uncompressed version of the
372 * trailing part (the malloc area passed in is freed).
373 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500374void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500375png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600376 png_size_t chunklength,
377 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600378{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600379 /* The caller should guarantee this */
380 if (prefix_size > chunklength)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600381 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600382 /* The recovery is to delete the chunk. */
383 png_warning(png_ptr, "invalid chunklength");
384 prefix_size = 0; /* To delete everything */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600385 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600386
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600387 else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600388 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600389 png_size_t expanded_size = png_inflate(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600390 (png_bytep)(png_ptr->chunkdata + prefix_size),
391 chunklength - prefix_size,
392 0, /*output*/
393 0); /*output size*/
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600394
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600395 /* Now check the limits on this chunk - if the limit fails the
396 * compressed data will be removed, the prefix will remain.
397 */
398#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
399 if (png_ptr->user_chunk_malloc_max &&
400 (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600401#else
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600402# ifdef PNG_USER_CHUNK_MALLOC_MAX
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600403 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
404 prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600405# endif
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600406#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600407 png_warning(png_ptr, "Exceeded size limit while expanding chunk");
408
409 /* If the size is zero either there was an error and a message
410 * has already been output (warning) or the size really is zero
411 * and we have nothing to do - the code will exit through the
412 * error case below.
413 */
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600414#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
415 defined(PNG_USER_CHUNK_MALLOC_MAX)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600416 else if (expanded_size > 0)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600417#else
418 if (expanded_size > 0)
419#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600420 {
421 /* Success (maybe) - really uncompress the chunk. */
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600422 png_size_t new_size = 0;
423 png_charp text = png_malloc_warn(png_ptr,
424 prefix_size + expanded_size + 1);
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600425
426 if (text != NULL)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600427 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600428 png_memcpy(text, png_ptr->chunkdata, prefix_size);
429 new_size = png_inflate(png_ptr,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600430 (png_bytep)(png_ptr->chunkdata + prefix_size),
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600431 chunklength - prefix_size,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600432 (png_bytep)(text + prefix_size), expanded_size);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600433 text[prefix_size + expanded_size] = 0; /* just in case */
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600434
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600435 if (new_size == expanded_size)
436 {
437 png_free(png_ptr, png_ptr->chunkdata);
438 png_ptr->chunkdata = text;
439 *newlength = prefix_size + expanded_size;
440 return; /* The success return! */
441 }
Glenn Randers-Pehrson821b7102010-06-24 16:16:32 -0500442
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600443 png_warning(png_ptr, "png_inflate logic error");
444 png_free(png_ptr, text);
445 }
446 else
447 png_warning(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600448 }
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600449 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600450
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600451 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
452 {
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600453#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600454 char umsg[50];
455
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600456 png_snprintf(umsg, sizeof umsg,
457 "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600458 png_warning(png_ptr, umsg);
459#else
460 png_warning(png_ptr, "Unknown zTXt compression type");
461#endif
462
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600463 /* The recovery is to simply drop the data. */
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600464 }
465
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600466 /* Generic error return - leave the prefix, delete the compressed
467 * data, reallocate the chunkdata to remove the potentially large
468 * amount of compressed data.
469 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600470 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600471 png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
472 if (text != NULL)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600473 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600474 if (prefix_size > 0)
Glenn Randers-Pehrson7d1f5912010-02-11 23:03:26 -0600475 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600476 png_free(png_ptr, png_ptr->chunkdata);
477 png_ptr->chunkdata = text;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600478
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600479 /* This is an extra zero in the 'uncompressed' part. */
480 *(png_ptr->chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500481 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600482 /* Ignore a malloc error here - it is safe. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600483 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600484
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600485 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600486}
487#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600488
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500489/* Read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500490void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600491png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500492{
493 png_byte buf[13];
494 png_uint_32 width, height;
495 int bit_depth, color_type, compression_type, filter_type;
496 int interlace_type;
497
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500498 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500499
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600500 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500501 png_error(png_ptr, "Out of place IHDR");
502
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500503 /* Check the length */
Guy Schalnat0d580581995-07-20 02:43:20 -0500504 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600505 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500506
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600507 png_ptr->mode |= PNG_HAVE_IHDR;
508
Guy Schalnat0d580581995-07-20 02:43:20 -0500509 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600510 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500511
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500512 width = png_get_uint_31(png_ptr, buf);
513 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500514 bit_depth = buf[8];
515 color_type = buf[9];
516 compression_type = buf[10];
517 filter_type = buf[11];
518 interlace_type = buf[12];
519
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500520 /* Set internal variables */
Guy Schalnat0d580581995-07-20 02:43:20 -0500521 png_ptr->width = width;
522 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600523 png_ptr->bit_depth = (png_byte)bit_depth;
524 png_ptr->interlaced = (png_byte)interlace_type;
525 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500526#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600527 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500528#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500529 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500530
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500531 /* Find number of channels */
Guy Schalnat0d580581995-07-20 02:43:20 -0500532 switch (png_ptr->color_type)
533 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500534 default: /* invalid, png_set_IHDR calls png_error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500535 case PNG_COLOR_TYPE_GRAY:
536 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500537 png_ptr->channels = 1;
538 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500539
Andreas Dilger47a0c421997-05-16 02:46:07 -0500540 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500541 png_ptr->channels = 3;
542 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500543
Andreas Dilger47a0c421997-05-16 02:46:07 -0500544 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500545 png_ptr->channels = 2;
546 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500547
Andreas Dilger47a0c421997-05-16 02:46:07 -0500548 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500549 png_ptr->channels = 4;
550 break;
551 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600552
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500553 /* Set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600554 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600555 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500556 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500557 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
558 png_debug1(3, "channels = %d", png_ptr->channels);
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -0600559 png_debug1(3, "rowbytes = %u", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500560 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600561 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500562}
563
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500564/* Read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500565void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600566png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500567{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600568 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600569 int num, i;
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500570#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500571 png_colorp pal_ptr;
572#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500573
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500574 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500575
Guy Schalnate5a37791996-06-05 15:50:50 -0500576 if (!(png_ptr->mode & PNG_HAVE_IHDR))
577 png_error(png_ptr, "Missing IHDR before PLTE");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500578
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600579 else if (png_ptr->mode & PNG_HAVE_IDAT)
580 {
581 png_warning(png_ptr, "Invalid PLTE after IDAT");
582 png_crc_finish(png_ptr, length);
583 return;
584 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500585
Guy Schalnate5a37791996-06-05 15:50:50 -0500586 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600587 png_error(png_ptr, "Duplicate PLTE chunk");
588
589 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500590
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500591 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
592 {
593 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600594 "Ignoring PLTE chunk in grayscale PNG");
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500595 png_crc_finish(png_ptr, length);
596 return;
597 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500598#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500599 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
600 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600601 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500602 return;
603 }
604#endif
605
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600606 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500607 {
608 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
609 {
610 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600611 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500612 return;
613 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500614
Guy Schalnate5a37791996-06-05 15:50:50 -0500615 else
616 {
617 png_error(png_ptr, "Invalid palette chunk");
618 }
619 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500620
621 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500622
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500623#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500624 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
625 {
626 png_byte buf[3];
627
628 png_crc_read(png_ptr, buf, 3);
629 pal_ptr->red = buf[0];
630 pal_ptr->green = buf[1];
631 pal_ptr->blue = buf[2];
632 }
633#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600634 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500635 {
636 png_byte buf[3];
637
638 png_crc_read(png_ptr, buf, 3);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500639 /* Don't depend upon png_color being any order */
Guy Schalnat0d580581995-07-20 02:43:20 -0500640 palette[i].red = buf[0];
641 palette[i].green = buf[1];
642 palette[i].blue = buf[2];
643 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500644#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600645
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600646 /* If we actually need the PLTE chunk (ie for a paletted image), we do
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500647 * whatever the normal CRC configuration tells us. However, if we
648 * have an RGB image, the PLTE can be considered ancillary, so
649 * we will act as though it is.
650 */
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500651#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600653#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600654 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500655 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600656 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500657#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600658 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
659 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600660 /* If we don't want to use the data from an ancillary chunk,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600661 * we have two options: an error abort, or a warning and we
662 * ignore the data in this chunk (which should be OK, since
663 * it's considered ancillary for a RGB or RGBA image).
664 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600665 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
666 {
667 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
668 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500669 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600670 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500671
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600672 else
673 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600674 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600675 return;
676 }
677 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500678 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600679 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
680 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600681 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600682 }
683 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600684#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500685
Andreas Dilger47a0c421997-05-16 02:46:07 -0500686 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500687
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500688#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500689 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
690 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600691 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500692 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500693 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500694 {
695 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500696 png_ptr->num_trans = (png_uint_16)num;
697 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500698
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500699 if (info_ptr->num_trans > (png_uint_16)num)
700 {
701 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
702 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500703 }
704 }
705 }
706#endif
707
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600708}
Guy Schalnate5a37791996-06-05 15:50:50 -0500709
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500710void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600711png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
712{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500713 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500714
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600715 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
716 {
717 png_error(png_ptr, "No image in file");
718 }
719
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600720 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600721
722 if (length != 0)
723 {
724 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600725 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500726
Andreas Dilger47a0c421997-05-16 02:46:07 -0500727 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500728
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500729 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500730}
731
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500732#ifdef PNG_READ_gAMA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500733void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600734png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500735{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600736 png_fixed_point igamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500737 png_byte buf[4];
738
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500739 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500740
Guy Schalnate5a37791996-06-05 15:50:50 -0500741 if (!(png_ptr->mode & PNG_HAVE_IHDR))
742 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600743 else if (png_ptr->mode & PNG_HAVE_IDAT)
744 {
745 png_warning(png_ptr, "Invalid gAMA after IDAT");
746 png_crc_finish(png_ptr, length);
747 return;
748 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500749 else if (png_ptr->mode & PNG_HAVE_PLTE)
750 /* Should be an error, but we can cope with it */
751 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600752
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500753 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500754#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600755 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600756#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600757 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600758 {
759 png_warning(png_ptr, "Duplicate gAMA chunk");
760 png_crc_finish(png_ptr, length);
761 return;
762 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500763
Guy Schalnat0d580581995-07-20 02:43:20 -0500764 if (length != 4)
765 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600766 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600767 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500768 return;
769 }
770
771 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600772 if (png_crc_finish(png_ptr, 0))
773 return;
774
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500775 igamma = png_get_fixed_point(NULL, buf);
776 /* Check for zero gamma or an error. */
777 if (igamma <= 0)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500778 {
779 png_warning(png_ptr,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500780 "Ignoring gAMA chunk with out of range gamma");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500781 return;
782 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500783
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500784#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600785 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500786 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600787 {
788 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600789 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500790#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600791 fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600792#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600793 return;
794 }
795#endif /* PNG_READ_sRGB_SUPPORTED */
796
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600797# ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500798 /* Gamma correction on read is supported. */
799 png_ptr->gamma = igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600800# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500801 /* And set the 'info' structure members. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600802 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500803}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500804#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500805
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500806#ifdef PNG_READ_sBIT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500807void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600808png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500809{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500810 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600811 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600812
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500813 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500814
Guy Schalnat69b14481996-01-10 02:56:49 -0600815 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500816
Guy Schalnate5a37791996-06-05 15:50:50 -0500817 if (!(png_ptr->mode & PNG_HAVE_IHDR))
818 png_error(png_ptr, "Missing IHDR before sBIT");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500819
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600820 else if (png_ptr->mode & PNG_HAVE_IDAT)
821 {
822 png_warning(png_ptr, "Invalid sBIT after IDAT");
823 png_crc_finish(png_ptr, length);
824 return;
825 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500826
Guy Schalnate5a37791996-06-05 15:50:50 -0500827 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600828 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500829 /* Should be an error, but we can cope with it */
830 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600831 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500832
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500833 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600834 {
835 png_warning(png_ptr, "Duplicate sBIT chunk");
836 png_crc_finish(png_ptr, length);
837 return;
838 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500839
Guy Schalnat0d580581995-07-20 02:43:20 -0500840 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600841 truelen = 3;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500842
Guy Schalnat0d580581995-07-20 02:43:20 -0500843 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500844 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500845
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500846 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500847 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600848 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600849 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600850 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500851 }
852
Andreas Dilger47a0c421997-05-16 02:46:07 -0500853 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500854
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600855 if (png_crc_finish(png_ptr, 0))
856 return;
857
Guy Schalnat0d580581995-07-20 02:43:20 -0500858 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
859 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600860 png_ptr->sig_bit.red = buf[0];
861 png_ptr->sig_bit.green = buf[1];
862 png_ptr->sig_bit.blue = buf[2];
863 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500864 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500865
Guy Schalnat0d580581995-07-20 02:43:20 -0500866 else
867 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600868 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600869 png_ptr->sig_bit.red = buf[0];
870 png_ptr->sig_bit.green = buf[0];
871 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600872 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500873 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500874
Andreas Dilger47a0c421997-05-16 02:46:07 -0500875 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500876}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500877#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500878
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500879#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500880void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600881png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500882{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500883 png_byte buf[32];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500884 png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue,
885 y_blue;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600886
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500887 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500888
Guy Schalnate5a37791996-06-05 15:50:50 -0500889 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600890 png_error(png_ptr, "Missing IHDR before cHRM");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500891
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600892 else if (png_ptr->mode & PNG_HAVE_IDAT)
893 {
894 png_warning(png_ptr, "Invalid cHRM after IDAT");
895 png_crc_finish(png_ptr, length);
896 return;
897 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500898
Guy Schalnate5a37791996-06-05 15:50:50 -0500899 else if (png_ptr->mode & PNG_HAVE_PLTE)
900 /* Should be an error, but we can cope with it */
901 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600902
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500903 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500904#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600905 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600906#endif
907 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600908 {
909 png_warning(png_ptr, "Duplicate cHRM chunk");
910 png_crc_finish(png_ptr, length);
911 return;
912 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500913
Guy Schalnat0d580581995-07-20 02:43:20 -0500914 if (length != 32)
915 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600916 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600917 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600918 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500919 }
920
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500921 png_crc_read(png_ptr, buf, 32);
922 if (png_crc_finish(png_ptr, 0))
923 return;
924
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500925 x_white = png_get_fixed_point(NULL, buf);
926 y_white = png_get_fixed_point(NULL, buf + 4);
927 x_red = png_get_fixed_point(NULL, buf + 8);
928 y_red = png_get_fixed_point(NULL, buf + 12);
929 x_green = png_get_fixed_point(NULL, buf + 16);
930 y_green = png_get_fixed_point(NULL, buf + 20);
931 x_blue = png_get_fixed_point(NULL, buf + 24);
932 y_blue = png_get_fixed_point(NULL, buf + 28);
933 if (x_white == PNG_FIXED_ERROR ||
934 y_white == PNG_FIXED_ERROR ||
935 x_red == PNG_FIXED_ERROR ||
936 y_red == PNG_FIXED_ERROR ||
937 x_green == PNG_FIXED_ERROR ||
938 y_green == PNG_FIXED_ERROR ||
939 x_blue == PNG_FIXED_ERROR ||
940 y_blue == PNG_FIXED_ERROR)
941 {
942 png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities");
943 return;
944 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600945
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500946#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500947 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500948 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500949 if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) ||
950 PNG_OUT_OF_RANGE(y_white, 32900, 1000) ||
951 PNG_OUT_OF_RANGE(x_red, 64000L, 1000) ||
952 PNG_OUT_OF_RANGE(y_red, 33000, 1000) ||
953 PNG_OUT_OF_RANGE(x_green, 30000, 1000) ||
954 PNG_OUT_OF_RANGE(y_green, 60000L, 1000) ||
955 PNG_OUT_OF_RANGE(x_blue, 15000, 1000) ||
956 PNG_OUT_OF_RANGE(y_blue, 6000, 1000))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500957 {
958 png_warning(png_ptr,
959 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500960#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500961 fprintf(stderr, "wx=%d, wy=%d, rx=%d, ry=%d\n",
962 x_white, y_white, x_red, y_red);
963 fprintf(stderr, "gx=%d, gy=%d, bx=%d, by=%d\n",
964 x_green, y_green, x_blue, y_blue);
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500965#endif /* PNG_CONSOLE_IO_SUPPORTED */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600966 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500967 return;
968 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600969#endif /* PNG_READ_sRGB_SUPPORTED */
970
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500971 png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
972 x_green, y_green, x_blue, y_blue);
Guy Schalnat0d580581995-07-20 02:43:20 -0500973}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500974#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500975
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500976#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500977void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600978png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
979{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600980 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600981 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600982
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500983 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600984
985 if (!(png_ptr->mode & PNG_HAVE_IHDR))
986 png_error(png_ptr, "Missing IHDR before sRGB");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500987
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600988 else if (png_ptr->mode & PNG_HAVE_IDAT)
989 {
990 png_warning(png_ptr, "Invalid sRGB after IDAT");
991 png_crc_finish(png_ptr, length);
992 return;
993 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500994
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600995 else if (png_ptr->mode & PNG_HAVE_PLTE)
996 /* Should be an error, but we can cope with it */
997 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600998
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500999 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001000 {
1001 png_warning(png_ptr, "Duplicate sRGB chunk");
1002 png_crc_finish(png_ptr, length);
1003 return;
1004 }
1005
1006 if (length != 1)
1007 {
1008 png_warning(png_ptr, "Incorrect sRGB chunk length");
1009 png_crc_finish(png_ptr, length);
1010 return;
1011 }
1012
1013 png_crc_read(png_ptr, buf, 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001014
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001015 if (png_crc_finish(png_ptr, 0))
1016 return;
1017
1018 intent = buf[0];
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001019 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001020 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001021 {
1022 png_warning(png_ptr, "Unknown sRGB intent");
1023 return;
1024 }
1025
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001026#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001027 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001028 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001029 if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001030 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001031 png_warning(png_ptr,
1032 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001033#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001034 fprintf(stderr, "incorrect gamma=(%d/100000)\n", info_ptr->gamma);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001035#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001036 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001037 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001038#endif /* PNG_READ_gAMA_SUPPORTED */
1039
1040#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001041 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001042 if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) ||
1043 PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) ||
1044 PNG_OUT_OF_RANGE(info_ptr->x_red, 64000L, 1000) ||
1045 PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) ||
1046 PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) ||
1047 PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) ||
1048 PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) ||
1049 PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001050 {
1051 png_warning(png_ptr,
1052 "Ignoring incorrect cHRM value when sRGB is also present");
1053 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001054#endif /* PNG_READ_cHRM_SUPPORTED */
1055
1056 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1057}
1058#endif /* PNG_READ_sRGB_SUPPORTED */
1059
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001060#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001061void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001062png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1063/* Note: this does not properly handle chunks that are > 64K under DOS */
1064{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001065 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001066 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001067 png_charp profile;
1068 png_uint_32 skip = 0;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001069 png_uint_32 profile_size;
1070 png_alloc_size_t profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001071 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001072
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001073 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001074
1075 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1076 png_error(png_ptr, "Missing IHDR before iCCP");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001077
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001078 else if (png_ptr->mode & PNG_HAVE_IDAT)
1079 {
1080 png_warning(png_ptr, "Invalid iCCP after IDAT");
1081 png_crc_finish(png_ptr, length);
1082 return;
1083 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001084
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001085 else if (png_ptr->mode & PNG_HAVE_PLTE)
1086 /* Should be an error, but we can cope with it */
1087 png_warning(png_ptr, "Out of place iCCP chunk");
1088
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001089 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001090 {
1091 png_warning(png_ptr, "Duplicate iCCP chunk");
1092 png_crc_finish(png_ptr, length);
1093 return;
1094 }
1095
1096#ifdef PNG_MAX_MALLOC_64K
1097 if (length > (png_uint_32)65535L)
1098 {
1099 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1100 skip = length - (png_uint_32)65535L;
1101 length = (png_uint_32)65535L;
1102 }
1103#endif
1104
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001105 png_free(png_ptr, png_ptr->chunkdata);
1106 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001107 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001108 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001109
1110 if (png_crc_finish(png_ptr, skip))
1111 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001112 png_free(png_ptr, png_ptr->chunkdata);
1113 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001114 return;
1115 }
1116
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001117 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001118
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001119 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001120 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001121
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001122 ++profile;
1123
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001124 /* There should be at least one zero (the compression type byte)
1125 * following the separator, and we should be on it
1126 */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001127 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001128 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001129 png_free(png_ptr, png_ptr->chunkdata);
1130 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001131 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001132 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001133 }
1134
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001135 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001136 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001137 if (compression_type)
1138 {
1139 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001140 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001141 wrote nonzero) */
1142 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001143
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001144 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001145 png_decompress_chunk(png_ptr, compression_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001146 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001147
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001148 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001149
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001150 if (prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001151 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001152 png_free(png_ptr, png_ptr->chunkdata);
1153 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001154 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1155 return;
1156 }
1157
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001158 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001159 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001160 profile_size = ((*(pC )) << 24) |
1161 ((*(pC + 1)) << 16) |
1162 ((*(pC + 2)) << 8) |
1163 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001164
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001165 /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
1166 * because profile_size is a 32 bit value.
1167 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001168 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001169 profile_length = profile_size;
1170
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001171 /* And the following guarantees that profile_size == profile_length. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001172 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001173 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001174 png_free(png_ptr, png_ptr->chunkdata);
1175 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001176#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001177 {
1178 char umsg[80];
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001179
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001180 png_snprintf2(umsg, 80,
1181 "Ignoring iCCP chunk with declared size = %u "
1182 "and actual length = %u", profile_size, profile_length);
1183 png_warning(png_ptr, umsg);
1184 }
1185#else
1186 png_warning(png_ptr,
1187 "Ignoring iCCP chunk with uncompressed size mismatch");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001188#endif
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001189 return;
1190 }
1191
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001192 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001193 compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001194 profile_size);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001195 png_free(png_ptr, png_ptr->chunkdata);
1196 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001197}
1198#endif /* PNG_READ_iCCP_SUPPORTED */
1199
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001200#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001201void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001202png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1203/* Note: this does not properly handle chunks that are > 64K under DOS */
1204{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001205 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001206 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001207#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001208 png_sPLT_entryp pp;
1209#endif
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001210 png_uint_32 data_length;
1211 int entry_size, i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001212 png_uint_32 skip = 0;
1213 png_size_t slength;
1214
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001215 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001216
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001217#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001218
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001219 if (png_ptr->user_chunk_cache_max != 0)
1220 {
1221 if (png_ptr->user_chunk_cache_max == 1)
1222 {
1223 png_crc_finish(png_ptr, length);
1224 return;
1225 }
1226 if (--png_ptr->user_chunk_cache_max == 1)
1227 {
1228 png_warning(png_ptr, "No space in chunk cache for sPLT");
1229 png_crc_finish(png_ptr, length);
1230 return;
1231 }
1232 }
1233#endif
1234
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001235 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1236 png_error(png_ptr, "Missing IHDR before sPLT");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001237
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001238 else if (png_ptr->mode & PNG_HAVE_IDAT)
1239 {
1240 png_warning(png_ptr, "Invalid sPLT after IDAT");
1241 png_crc_finish(png_ptr, length);
1242 return;
1243 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001244
1245#ifdef PNG_MAX_MALLOC_64K
1246 if (length > (png_uint_32)65535L)
1247 {
1248 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1249 skip = length - (png_uint_32)65535L;
1250 length = (png_uint_32)65535L;
1251 }
1252#endif
1253
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001254 png_free(png_ptr, png_ptr->chunkdata);
1255 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001256
1257 /* WARNING: this may break if size_t is less than 32 bits; it is assumed
1258 * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
1259 * potential breakage point if the types in pngconf.h aren't exactly right.
1260 */
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001261 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001262 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001263
1264 if (png_crc_finish(png_ptr, skip))
1265 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001266 png_free(png_ptr, png_ptr->chunkdata);
1267 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001268 return;
1269 }
1270
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001271 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001272
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001273 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1274 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001275 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001276
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001277 ++entry_start;
1278
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001279 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001280 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001281 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001282 png_free(png_ptr, png_ptr->chunkdata);
1283 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001284 png_warning(png_ptr, "malformed sPLT chunk");
1285 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001286 }
1287
1288 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001289 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001290 /* This must fit in a png_uint_32 because it is derived from the original
1291 * chunk data length (and use 'length', not 'slength' here for clarity -
1292 * they are guaranteed to be the same, see the tests above.)
1293 */
1294 data_length = length - (png_uint_32)(entry_start -
1295 (png_bytep)png_ptr->chunkdata);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001296
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001297 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001298 if (data_length % entry_size)
1299 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001300 png_free(png_ptr, png_ptr->chunkdata);
1301 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001302 png_warning(png_ptr, "sPLT chunk has bad length");
1303 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001304 }
1305
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001306 if ((data_length / entry_size) > (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001307 {
1308 png_warning(png_ptr, "sPLT chunk too long");
1309 return;
1310 }
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001311 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001312
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001313 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001314 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001315
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001316 if (new_palette.entries == NULL)
1317 {
1318 png_warning(png_ptr, "sPLT chunk requires too much memory");
1319 return;
1320 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001321
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001322#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001323 for (i = 0; i < new_palette.nentries; i++)
1324 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001325 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001326
1327 if (new_palette.depth == 8)
1328 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001329 pp->red = *entry_start++;
1330 pp->green = *entry_start++;
1331 pp->blue = *entry_start++;
1332 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001333 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001334
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001335 else
1336 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001337 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1338 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1339 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1340 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001341 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001342
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001343 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1344 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001345#else
1346 pp = new_palette.entries;
1347 for (i = 0; i < new_palette.nentries; i++)
1348 {
1349
1350 if (new_palette.depth == 8)
1351 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001352 pp[i].red = *entry_start++;
1353 pp[i].green = *entry_start++;
1354 pp[i].blue = *entry_start++;
1355 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001356 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001357
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001358 else
1359 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001360 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1361 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1362 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1363 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001364 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001365
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001366 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1367 }
1368#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001369
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001370 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001371 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001372
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001373 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001374
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001375 png_free(png_ptr, png_ptr->chunkdata);
1376 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001377 png_free(png_ptr, new_palette.entries);
1378}
1379#endif /* PNG_READ_sPLT_SUPPORTED */
1380
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001381#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001382void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001383png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001384{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001385 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001386
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001387 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001388
Guy Schalnate5a37791996-06-05 15:50:50 -05001389 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1390 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001391 else if (png_ptr->mode & PNG_HAVE_IDAT)
1392 {
1393 png_warning(png_ptr, "Invalid tRNS after IDAT");
1394 png_crc_finish(png_ptr, length);
1395 return;
1396 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001397
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001398 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001399 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001400 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001401 png_crc_finish(png_ptr, length);
1402 return;
1403 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001404
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001405 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001406 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001407 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001408
1409 if (length != 2)
1410 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001411 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001412 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001413 return;
1414 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001415
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001416 png_crc_read(png_ptr, buf, 2);
1417 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001418 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001419 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001420
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001421 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1422 {
1423 png_byte buf[6];
1424
1425 if (length != 6)
1426 {
1427 png_warning(png_ptr, "Incorrect tRNS chunk length");
1428 png_crc_finish(png_ptr, length);
1429 return;
1430 }
1431 png_crc_read(png_ptr, buf, (png_size_t)length);
1432 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001433 png_ptr->trans_color.red = png_get_uint_16(buf);
1434 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1435 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001436 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001437
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001438 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1439 {
1440 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1441 {
1442 /* Should be an error, but we can cope with it. */
1443 png_warning(png_ptr, "Missing PLTE before tRNS");
1444 }
1445 if (length > (png_uint_32)png_ptr->num_palette ||
1446 length > PNG_MAX_PALETTE_LENGTH)
1447 {
1448 png_warning(png_ptr, "Incorrect tRNS chunk length");
1449 png_crc_finish(png_ptr, length);
1450 return;
1451 }
1452 if (length == 0)
1453 {
1454 png_warning(png_ptr, "Zero length tRNS chunk");
1455 png_crc_finish(png_ptr, length);
1456 return;
1457 }
1458 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1459 png_ptr->num_trans = (png_uint_16)length;
1460 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001461
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001462 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001463 {
1464 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001465 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001466 return;
1467 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001468
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001469 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001470 {
1471 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001472 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001473 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001474
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001475 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001476 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001477}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001478#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001479
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001480#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001481void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001482png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001483{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001484 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001485 png_byte buf[6];
1486
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001487 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001488
Guy Schalnate5a37791996-06-05 15:50:50 -05001489 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1490 png_error(png_ptr, "Missing IHDR before bKGD");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001491
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001492 else if (png_ptr->mode & PNG_HAVE_IDAT)
1493 {
1494 png_warning(png_ptr, "Invalid bKGD after IDAT");
1495 png_crc_finish(png_ptr, length);
1496 return;
1497 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001498
Guy Schalnate5a37791996-06-05 15:50:50 -05001499 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001500 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001501 {
1502 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001503 png_crc_finish(png_ptr, length);
1504 return;
1505 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001506
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001507 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001508 {
1509 png_warning(png_ptr, "Duplicate bKGD chunk");
1510 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001511 return;
1512 }
1513
Guy Schalnat0d580581995-07-20 02:43:20 -05001514 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1515 truelen = 1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001516
Guy Schalnat0d580581995-07-20 02:43:20 -05001517 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1518 truelen = 6;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001519
Guy Schalnat0d580581995-07-20 02:43:20 -05001520 else
1521 truelen = 2;
1522
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001523 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001524 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001525 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001526 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001527 return;
1528 }
1529
Andreas Dilger47a0c421997-05-16 02:46:07 -05001530 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001531
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001532 if (png_crc_finish(png_ptr, 0))
1533 return;
1534
Guy Schalnate5a37791996-06-05 15:50:50 -05001535 /* We convert the index value into RGB components so that we can allow
1536 * arbitrary RGB values for background when we have transparency, and
1537 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001538 * from the info_ptr struct.
1539 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001540 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001541 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001542 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001543 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001544 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001545 if (buf[0] >= info_ptr->num_palette)
1546 {
1547 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1548 return;
1549 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001550
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001551 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001552 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001553
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001554 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001555 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001556
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001557 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001558 (png_uint_16)png_ptr->palette[buf[0]].blue;
1559 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001560 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001561
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001563 {
1564 png_ptr->background.red =
1565 png_ptr->background.green =
1566 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001567 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001568 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001569
Guy Schalnat0d580581995-07-20 02:43:20 -05001570 else
1571 {
1572 png_ptr->background.red = png_get_uint_16(buf);
1573 png_ptr->background.green = png_get_uint_16(buf + 2);
1574 png_ptr->background.blue = png_get_uint_16(buf + 4);
1575 }
1576
Andreas Dilger47a0c421997-05-16 02:46:07 -05001577 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001578}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001579#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001580
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001581#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001582void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001583png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001584{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001585 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001586 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001587
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001588 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001589
Guy Schalnate5a37791996-06-05 15:50:50 -05001590 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1591 png_error(png_ptr, "Missing IHDR before hIST");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001592
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001593 else if (png_ptr->mode & PNG_HAVE_IDAT)
1594 {
1595 png_warning(png_ptr, "Invalid hIST after IDAT");
1596 png_crc_finish(png_ptr, length);
1597 return;
1598 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001599
Guy Schalnate5a37791996-06-05 15:50:50 -05001600 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1601 {
1602 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001603 png_crc_finish(png_ptr, length);
1604 return;
1605 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001606
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001607 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001608 {
1609 png_warning(png_ptr, "Duplicate hIST chunk");
1610 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001611 return;
1612 }
1613
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001614 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001615 if (num != (unsigned int) png_ptr->num_palette || num >
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001616 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001617 {
1618 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001619 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001620 return;
1621 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001622
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001623 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001624 {
1625 png_byte buf[2];
1626
1627 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001628 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001629 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001630
1631 if (png_crc_finish(png_ptr, 0))
1632 return;
1633
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001634 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001635}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001636#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001637
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001638#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001639void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001640png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001641{
1642 png_byte buf[9];
1643 png_uint_32 res_x, res_y;
1644 int unit_type;
1645
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001646 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001647
Guy Schalnate5a37791996-06-05 15:50:50 -05001648 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001649 png_error(png_ptr, "Missing IHDR before pHYs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001650
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001651 else if (png_ptr->mode & PNG_HAVE_IDAT)
1652 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001653 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001654 png_crc_finish(png_ptr, length);
1655 return;
1656 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001657
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001658 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001659 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001660 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001661 png_crc_finish(png_ptr, length);
1662 return;
1663 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001664
Guy Schalnat0d580581995-07-20 02:43:20 -05001665 if (length != 9)
1666 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001667 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001668 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001669 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001670 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001671
1672 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001673
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001674 if (png_crc_finish(png_ptr, 0))
1675 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001676
1677 res_x = png_get_uint_32(buf);
1678 res_y = png_get_uint_32(buf + 4);
1679 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001680 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001681}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001682#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001683
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001684#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001685void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001686png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001687{
1688 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001689 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001690 int unit_type;
1691
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001692 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001693
Guy Schalnate5a37791996-06-05 15:50:50 -05001694 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1695 png_error(png_ptr, "Missing IHDR before oFFs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001696
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001697 else if (png_ptr->mode & PNG_HAVE_IDAT)
1698 {
1699 png_warning(png_ptr, "Invalid oFFs after IDAT");
1700 png_crc_finish(png_ptr, length);
1701 return;
1702 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001703
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001704 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001705 {
1706 png_warning(png_ptr, "Duplicate oFFs chunk");
1707 png_crc_finish(png_ptr, length);
1708 return;
1709 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001710
Guy Schalnat0d580581995-07-20 02:43:20 -05001711 if (length != 9)
1712 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001713 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001714 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001715 return;
1716 }
1717
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001718 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001719
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001720 if (png_crc_finish(png_ptr, 0))
1721 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001722
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001723 offset_x = png_get_int_32(buf);
1724 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001725 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001726 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1727}
1728#endif
1729
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001730#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001731/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001732void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001733png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1734{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001735 png_int_32 X0, X1;
1736 png_byte type, nparams;
1737 png_charp buf, units, endptr;
1738 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001739 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001740 int i;
1741
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001742 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001743
1744 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1745 png_error(png_ptr, "Missing IHDR before pCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001746
Andreas Dilger47a0c421997-05-16 02:46:07 -05001747 else if (png_ptr->mode & PNG_HAVE_IDAT)
1748 {
1749 png_warning(png_ptr, "Invalid pCAL after IDAT");
1750 png_crc_finish(png_ptr, length);
1751 return;
1752 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001753
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001754 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001755 {
1756 png_warning(png_ptr, "Duplicate pCAL chunk");
1757 png_crc_finish(png_ptr, length);
1758 return;
1759 }
1760
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001761 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001762 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001763 png_free(png_ptr, png_ptr->chunkdata);
1764 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001765
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001766 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001767 {
1768 png_warning(png_ptr, "No memory for pCAL purpose");
1769 return;
1770 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001771
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001772 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001773 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001774
1775 if (png_crc_finish(png_ptr, 0))
1776 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001777 png_free(png_ptr, png_ptr->chunkdata);
1778 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001779 return;
1780 }
1781
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001782 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001783
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001784 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001785 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001786 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001788 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001789
1790 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001791 * in order to get the parameter information.
1792 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001793 if (endptr <= buf + 12)
1794 {
1795 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001796 png_free(png_ptr, png_ptr->chunkdata);
1797 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001798 return;
1799 }
1800
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001801 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001802 X0 = png_get_int_32((png_bytep)buf+1);
1803 X1 = png_get_int_32((png_bytep)buf+5);
1804 type = buf[9];
1805 nparams = buf[10];
1806 units = buf + 11;
1807
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001808 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001809 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001810 * equation types.
1811 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001812 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1813 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1814 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1815 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1816 {
1817 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001818 png_free(png_ptr, png_ptr->chunkdata);
1819 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001820 return;
1821 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001822
Andreas Dilger47a0c421997-05-16 02:46:07 -05001823 else if (type >= PNG_EQUATION_LAST)
1824 {
1825 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1826 }
1827
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001828 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001829 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001830
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001831 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001832 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001833 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001834 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001835 {
1836 png_free(png_ptr, png_ptr->chunkdata);
1837 png_ptr->chunkdata = NULL;
1838 png_warning(png_ptr, "No memory for pCAL params");
1839 return;
1840 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001841
1842 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001843 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001844 {
1845 buf++; /* Skip the null string terminator from previous parameter. */
1846
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001847 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001848 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001849 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001850
1851 /* Make sure we haven't run out of data yet */
1852 if (buf > endptr)
1853 {
1854 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001855 png_free(png_ptr, png_ptr->chunkdata);
1856 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001857 png_free(png_ptr, params);
1858 return;
1859 }
1860 }
1861
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001862 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001863 units, params);
1864
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001865 png_free(png_ptr, png_ptr->chunkdata);
1866 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001867 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001868}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001869#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001870
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001871#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001872/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001873void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001874png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1875{
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001876 png_size_t slength, index;
1877 int state;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001878
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001879 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001880
1881 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1882 png_error(png_ptr, "Missing IHDR before sCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001883
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001884 else if (png_ptr->mode & PNG_HAVE_IDAT)
1885 {
1886 png_warning(png_ptr, "Invalid sCAL after IDAT");
1887 png_crc_finish(png_ptr, length);
1888 return;
1889 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001890
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001891 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001892 {
1893 png_warning(png_ptr, "Duplicate sCAL chunk");
1894 png_crc_finish(png_ptr, length);
1895 return;
1896 }
1897
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001898 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001899 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001900 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001901
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001902 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001903 {
1904 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05001905 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001906 return;
1907 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001908
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001909 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001910 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001911 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001912
1913 if (png_crc_finish(png_ptr, 0))
1914 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001915 png_free(png_ptr, png_ptr->chunkdata);
1916 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001917 return;
1918 }
1919
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001920 /* Validate the unit. */
1921 if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001922 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001923 png_warning(png_ptr, "Invalid sCAL ignored: invalid unit");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05001924 png_free(png_ptr, png_ptr->chunkdata);
1925 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001926 return;
1927 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001928
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001929 /* Validate the ASCII numbers, need two ASCII numbers separated by
1930 * a '\0' and they need to fit exactly in the chunk data.
1931 */
1932 index = 0;
1933 state = 0;
1934 if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
1935 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
1936 index >= slength || png_ptr->chunkdata[index++] != 0)
1937 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
1938 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001939 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001940 png_size_t heighti = index;
1941 if (png_ptr->chunkdata[index] == 45 /* negative height */ ||
1942 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001943 index != slength)
1944 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001945 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001946 /* This is the (only) success case. */
1947 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
1948 png_ptr->chunkdata+1, png_ptr->chunkdata+heighti);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001949 }
1950
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001951 /* Clean up - just free the temporarily allocated buffer. */
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001952 png_free(png_ptr, png_ptr->chunkdata);
1953 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001954}
1955#endif
1956
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001957#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001958void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001959png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001960{
1961 png_byte buf[7];
1962 png_time mod_time;
1963
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001964 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001965
Guy Schalnate5a37791996-06-05 15:50:50 -05001966 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001967 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001968
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001969 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001970 {
1971 png_warning(png_ptr, "Duplicate tIME chunk");
1972 png_crc_finish(png_ptr, length);
1973 return;
1974 }
1975
1976 if (png_ptr->mode & PNG_HAVE_IDAT)
1977 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001978
Guy Schalnat0d580581995-07-20 02:43:20 -05001979 if (length != 7)
1980 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001981 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001982 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001983 return;
1984 }
1985
1986 png_crc_read(png_ptr, buf, 7);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001987
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001988 if (png_crc_finish(png_ptr, 0))
1989 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001990
1991 mod_time.second = buf[6];
1992 mod_time.minute = buf[5];
1993 mod_time.hour = buf[4];
1994 mod_time.day = buf[3];
1995 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001996 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001997
Andreas Dilger47a0c421997-05-16 02:46:07 -05001998 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001999}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002000#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002001
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002002#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002003/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002004void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002005png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002006{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002007 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002008 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06002009 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002010 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002011 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002012 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002013
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002014 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05002015
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002016#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002017 if (png_ptr->user_chunk_cache_max != 0)
2018 {
2019 if (png_ptr->user_chunk_cache_max == 1)
2020 {
2021 png_crc_finish(png_ptr, length);
2022 return;
2023 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002024
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002025 if (--png_ptr->user_chunk_cache_max == 1)
2026 {
2027 png_warning(png_ptr, "No space in chunk cache for tEXt");
2028 png_crc_finish(png_ptr, length);
2029 return;
2030 }
2031 }
2032#endif
2033
Guy Schalnate5a37791996-06-05 15:50:50 -05002034 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2035 png_error(png_ptr, "Missing IHDR before tEXt");
2036
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002037 if (png_ptr->mode & PNG_HAVE_IDAT)
2038 png_ptr->mode |= PNG_AFTER_IDAT;
2039
Andreas Dilger47a0c421997-05-16 02:46:07 -05002040#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002041 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002042 {
2043 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002044 skip = length - (png_uint_32)65535L;
2045 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002046 }
2047#endif
2048
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002049 png_free(png_ptr, png_ptr->chunkdata);
2050
2051 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2052 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002053 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002054 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002055 return;
2056 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002057 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002058 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002059
2060 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002061 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002062 png_free(png_ptr, png_ptr->chunkdata);
2063 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002064 return;
2065 }
2066
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002067 key = png_ptr->chunkdata;
2068
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002069 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002070
2071 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002072 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002073
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002074 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002075 text++;
2076
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002077 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002078 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002079
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002080 if (text_ptr == NULL)
2081 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002082 png_warning(png_ptr, "Not enough memory to process text chunk");
2083 png_free(png_ptr, png_ptr->chunkdata);
2084 png_ptr->chunkdata = NULL;
2085 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002086 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002087
Andreas Dilger47a0c421997-05-16 02:46:07 -05002088 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2089 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002090 text_ptr->lang = NULL;
2091 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002092 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002093 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002094 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002095
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002096 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002097
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002098 png_free(png_ptr, png_ptr->chunkdata);
2099 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002100 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002101
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002102 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002103 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002104}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002105#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002106
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002107#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002108/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002109void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002110png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002111{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002112 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002113 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002114 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002115 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002116 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002117
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002118 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002119
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002120#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002121 if (png_ptr->user_chunk_cache_max != 0)
2122 {
2123 if (png_ptr->user_chunk_cache_max == 1)
2124 {
2125 png_crc_finish(png_ptr, length);
2126 return;
2127 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002128
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002129 if (--png_ptr->user_chunk_cache_max == 1)
2130 {
2131 png_warning(png_ptr, "No space in chunk cache for zTXt");
2132 png_crc_finish(png_ptr, length);
2133 return;
2134 }
2135 }
2136#endif
2137
Guy Schalnate5a37791996-06-05 15:50:50 -05002138 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2139 png_error(png_ptr, "Missing IHDR before zTXt");
2140
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002141 if (png_ptr->mode & PNG_HAVE_IDAT)
2142 png_ptr->mode |= PNG_AFTER_IDAT;
2143
Andreas Dilger47a0c421997-05-16 02:46:07 -05002144#ifdef PNG_MAX_MALLOC_64K
2145 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002146 * there is no hard and fast rule to tell us where to stop.
2147 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002148 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002149 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002150 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2151 png_crc_finish(png_ptr, length);
2152 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002153 }
2154#endif
2155
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002156 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002157 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2158 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002159 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002160 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2161 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002162 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002163
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002164 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002165 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002166
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002167 if (png_crc_finish(png_ptr, 0))
2168 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002169 png_free(png_ptr, png_ptr->chunkdata);
2170 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002171 return;
2172 }
2173
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002174 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002175
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002176 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002177 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002178
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002179 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002180 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002181 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002182 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002183 png_free(png_ptr, png_ptr->chunkdata);
2184 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002185 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002186 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002187
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002188 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002189 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002190 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002191 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2192 {
2193 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2194 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2195 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002196 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002197 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002198
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002199 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002200
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002201 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002202 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002203
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002204 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002205 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002206
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002207 if (text_ptr == NULL)
2208 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002209 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2210 png_free(png_ptr, png_ptr->chunkdata);
2211 png_ptr->chunkdata = NULL;
2212 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002213 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002214
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002215 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002216 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002217 text_ptr->lang = NULL;
2218 text_ptr->lang_key = NULL;
2219 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002220 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002221 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002222
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002223 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002224
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002225 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002226 png_free(png_ptr, png_ptr->chunkdata);
2227 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002228
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002229 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002230 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002231}
2232#endif
2233
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002234#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002235/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002236void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002237png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2238{
2239 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002240 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002241 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002242 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002243 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002244 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002245
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002246 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002247
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002248#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002249 if (png_ptr->user_chunk_cache_max != 0)
2250 {
2251 if (png_ptr->user_chunk_cache_max == 1)
2252 {
2253 png_crc_finish(png_ptr, length);
2254 return;
2255 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002256
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002257 if (--png_ptr->user_chunk_cache_max == 1)
2258 {
2259 png_warning(png_ptr, "No space in chunk cache for iTXt");
2260 png_crc_finish(png_ptr, length);
2261 return;
2262 }
2263 }
2264#endif
2265
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002266 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2267 png_error(png_ptr, "Missing IHDR before iTXt");
2268
2269 if (png_ptr->mode & PNG_HAVE_IDAT)
2270 png_ptr->mode |= PNG_AFTER_IDAT;
2271
2272#ifdef PNG_MAX_MALLOC_64K
2273 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002274 * there is no hard and fast rule to tell us where to stop.
2275 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002276 if (length > (png_uint_32)65535L)
2277 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002278 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2279 png_crc_finish(png_ptr, length);
2280 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002281 }
2282#endif
2283
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002284 png_free(png_ptr, png_ptr->chunkdata);
2285 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2286 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002287 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002288 png_warning(png_ptr, "No memory to process iTXt chunk");
2289 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002290 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002291 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002292 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002293
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002294 if (png_crc_finish(png_ptr, 0))
2295 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002296 png_free(png_ptr, png_ptr->chunkdata);
2297 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002298 return;
2299 }
2300
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002301 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002302
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002303 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002304 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002305
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002306 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002307
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002308 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002309 * translated keyword (possibly empty), and possibly some text after the
2310 * keyword
2311 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002312
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002313 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002314 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002315 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002316 png_free(png_ptr, png_ptr->chunkdata);
2317 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002318 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002319 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002320
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002321 else
2322 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002323 comp_flag = *lang++;
2324 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002325 }
2326
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002327 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002328 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002329
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002330 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002331
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002332 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002333 {
2334 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002335 png_free(png_ptr, png_ptr->chunkdata);
2336 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002337 return;
2338 }
2339
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002340 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002341 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002342
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002343 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002344
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002345 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002346 {
2347 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002348 png_free(png_ptr, png_ptr->chunkdata);
2349 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002350 return;
2351 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002352
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002353 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002354
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002355 key=png_ptr->chunkdata;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002356
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002357 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002358 png_decompress_chunk(png_ptr, comp_type,
2359 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002360
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002361 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002362 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002363
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002364 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002365 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002366
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002367 if (text_ptr == NULL)
2368 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002369 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2370 png_free(png_ptr, png_ptr->chunkdata);
2371 png_ptr->chunkdata = NULL;
2372 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002373 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002374
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002375 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002376 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2377 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002378 text_ptr->itxt_length = data_len;
2379 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002380 text_ptr->key = png_ptr->chunkdata;
2381 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002382
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002383 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002384
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002385 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002386 png_free(png_ptr, png_ptr->chunkdata);
2387 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002388
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002389 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002390 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002391}
2392#endif
2393
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002394/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002395 * chunk. If there isn't a problem with the chunk itself (ie bad
2396 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2397 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2398 * case it will be saved away to be written out later.
2399 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002400void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002401png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2402{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002403 png_uint_32 skip = 0;
2404
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002405 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002406
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002407#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002408 if (png_ptr->user_chunk_cache_max != 0)
2409 {
2410 if (png_ptr->user_chunk_cache_max == 1)
2411 {
2412 png_crc_finish(png_ptr, length);
2413 return;
2414 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002415
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002416 if (--png_ptr->user_chunk_cache_max == 1)
2417 {
2418 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2419 png_crc_finish(png_ptr, length);
2420 return;
2421 }
2422 }
2423#endif
2424
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002425 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002426 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002427 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002428 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002429 png_ptr->mode |= PNG_AFTER_IDAT;
2430 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002431
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002432 if (!(png_ptr->chunk_name[0] & 0x20))
2433 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002434#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002435 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002436 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002437#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002438 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002439#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002440 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002441#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002442 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002443 }
2444
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002445#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002446 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002447#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002448 || (png_ptr->read_user_chunk_fn != NULL)
2449#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002450 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002451 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002452#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002453 if (length > (png_uint_32)65535L)
2454 {
2455 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2456 skip = length - (png_uint_32)65535L;
2457 length = (png_uint_32)65535L;
2458 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002459#endif
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002460
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002461 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2462 (png_charp)png_ptr->chunk_name,
2463 png_sizeof(png_ptr->unknown_chunk.name));
2464 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2465 = '\0';
2466 png_ptr->unknown_chunk.size = (png_size_t)length;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002467
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002468 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002469 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002470
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002471 else
2472 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002473 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2474 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002475 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002476
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002477#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002478 if (png_ptr->read_user_chunk_fn != NULL)
2479 {
2480 /* Callback to user unknown chunk handler */
2481 int ret;
2482 ret = (*(png_ptr->read_user_chunk_fn))
2483 (png_ptr, &png_ptr->unknown_chunk);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002484
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002485 if (ret < 0)
2486 png_chunk_error(png_ptr, "error in user chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002487
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002488 if (ret == 0)
2489 {
2490 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002491#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002492 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2493 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002494#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002495 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002496
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002497 png_set_unknown_chunks(png_ptr, info_ptr,
2498 &png_ptr->unknown_chunk, 1);
2499 }
2500 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002501
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002502 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002503#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002504 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002505
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002506 png_free(png_ptr, png_ptr->unknown_chunk.data);
2507 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002508 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002509
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002510 else
2511#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002512 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002513
2514 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002515
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002516#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002517 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002518#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002519}
2520
2521/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002522 * This function can't have the "critical chunk check" incorporated
2523 * into it, since in the future we will need to be able to call user
2524 * functions to handle unknown critical chunks after we check that
2525 * the chunk name itself is valid.
2526 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002527
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002528#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002529
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002530void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002531png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002532{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002533 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002534 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002535 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002536 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002537 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002538 }
2539}
2540
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002541/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002542 * row. This routine takes care of alpha and transparency if requested.
2543 * This routine also handles the two methods of progressive display
2544 * of interlaced images, depending on the mask value.
2545 * The mask value describes which pixels are to be combined with
2546 * the row. The pattern always repeats every 8 pixels, so just 8
2547 * bits are needed. A one indicates the pixel is to be combined,
2548 * a zero indicates the pixel is to be skipped. This is in addition
2549 * to any alpha or transparency value associated with the pixel. If
2550 * you want all pixels to be combined, pass 0xff (255) in mask.
2551 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002552
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002553void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002554png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002555{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002556 png_debug(1, "in png_combine_row");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002557
Guy Schalnat0d580581995-07-20 02:43:20 -05002558 if (mask == 0xff)
2559 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002560 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002561 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002562 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002563
Guy Schalnat0d580581995-07-20 02:43:20 -05002564 else
2565 {
2566 switch (png_ptr->row_info.pixel_depth)
2567 {
2568 case 1:
2569 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002570 png_bytep sp = png_ptr->row_buf + 1;
2571 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002572 int s_inc, s_start, s_end;
2573 int m = 0x80;
2574 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002575 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002576 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002577
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002578#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002579 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002580 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002581 s_start = 0;
2582 s_end = 7;
2583 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002584 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002585
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002586 else
2587#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002588 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002589 s_start = 7;
2590 s_end = 0;
2591 s_inc = -1;
2592 }
2593
2594 shift = s_start;
2595
2596 for (i = 0; i < row_width; i++)
2597 {
2598 if (m & mask)
2599 {
2600 int value;
2601
2602 value = (*sp >> shift) & 0x01;
2603 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2604 *dp |= (png_byte)(value << shift);
2605 }
2606
2607 if (shift == s_end)
2608 {
2609 shift = s_start;
2610 sp++;
2611 dp++;
2612 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002613
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002614 else
2615 shift += s_inc;
2616
2617 if (m == 1)
2618 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002619
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002620 else
2621 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002622 }
2623 break;
2624 }
2625 case 2:
2626 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002627 png_bytep sp = png_ptr->row_buf + 1;
2628 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002629 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002630 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002631 int shift;
2632 png_uint_32 i;
2633 png_uint_32 row_width = png_ptr->width;
2634 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002635
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002636#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002637 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002638 {
2639 s_start = 0;
2640 s_end = 6;
2641 s_inc = 2;
2642 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002643
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002644 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002645#endif
2646 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002647 s_start = 6;
2648 s_end = 0;
2649 s_inc = -2;
2650 }
2651
2652 shift = s_start;
2653
2654 for (i = 0; i < row_width; i++)
2655 {
2656 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002657 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002658 value = (*sp >> shift) & 0x03;
2659 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2660 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002661 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002662
2663 if (shift == s_end)
2664 {
2665 shift = s_start;
2666 sp++;
2667 dp++;
2668 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002669
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002670 else
2671 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002672
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002673 if (m == 1)
2674 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002675
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002676 else
2677 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002678 }
2679 break;
2680 }
2681 case 4:
2682 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002683 png_bytep sp = png_ptr->row_buf + 1;
2684 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002685 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002686 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002687 int shift;
2688 png_uint_32 i;
2689 png_uint_32 row_width = png_ptr->width;
2690 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002691
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002692#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002693 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002694 {
2695 s_start = 0;
2696 s_end = 4;
2697 s_inc = 4;
2698 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -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 s_start = 4;
2704 s_end = 0;
2705 s_inc = -4;
2706 }
2707 shift = s_start;
2708
2709 for (i = 0; i < row_width; i++)
2710 {
2711 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002712 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002713 value = (*sp >> shift) & 0xf;
2714 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2715 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002716 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002717
2718 if (shift == s_end)
2719 {
2720 shift = s_start;
2721 sp++;
2722 dp++;
2723 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002724
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002725 else
2726 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002727
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002728 if (m == 1)
2729 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002730
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002731 else
2732 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002733 }
2734 break;
2735 }
2736 default:
2737 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002738 png_bytep sp = png_ptr->row_buf + 1;
2739 png_bytep dp = row;
2740 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2741 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002742 png_uint_32 row_width = png_ptr->width;
2743 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002744
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002745
2746 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002747 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002748 if (m & mask)
2749 {
2750 png_memcpy(dp, sp, pixel_bytes);
2751 }
2752
2753 sp += pixel_bytes;
2754 dp += pixel_bytes;
2755
2756 if (m == 1)
2757 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002758
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002759 else
2760 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002761 }
2762 break;
2763 }
2764 }
2765 }
2766}
2767
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002768#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002769void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002770png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002771{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002772 png_row_infop row_info = &(png_ptr->row_info);
2773 png_bytep row = png_ptr->row_buf + 1;
2774 int pass = png_ptr->pass;
2775 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002776 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2777 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002778 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002779
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002780 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002781 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002782 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002783 png_uint_32 final_width;
2784
2785 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002786
2787 switch (row_info->pixel_depth)
2788 {
2789 case 1:
2790 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002791 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2792 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002793 int sshift, dshift;
2794 int s_start, s_end, s_inc;
2795 int jstop = png_pass_inc[pass];
2796 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002797 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002798 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002799
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002800#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002801 if (transformations & PNG_PACKSWAP)
2802 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002803 sshift = (int)((row_info->width + 7) & 0x07);
2804 dshift = (int)((final_width + 7) & 0x07);
2805 s_start = 7;
2806 s_end = 0;
2807 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002808 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002809
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002810 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002811#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002812 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002813 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2814 dshift = 7 - (int)((final_width + 7) & 0x07);
2815 s_start = 0;
2816 s_end = 7;
2817 s_inc = 1;
2818 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002819
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002820 for (i = 0; i < row_info->width; i++)
2821 {
2822 v = (png_byte)((*sp >> sshift) & 0x01);
2823 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002824 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002825 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2826 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002827
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002828 if (dshift == s_end)
2829 {
2830 dshift = s_start;
2831 dp--;
2832 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002833
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002834 else
2835 dshift += s_inc;
2836 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002837
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002838 if (sshift == s_end)
2839 {
2840 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002841 sp--;
2842 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002843
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002844 else
2845 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002846 }
2847 break;
2848 }
2849 case 2:
2850 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002851 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2852 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2853 int sshift, dshift;
2854 int s_start, s_end, s_inc;
2855 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002856 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002857
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002858#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002859 if (transformations & PNG_PACKSWAP)
2860 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002861 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2862 dshift = (int)(((final_width + 3) & 0x03) << 1);
2863 s_start = 6;
2864 s_end = 0;
2865 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002866 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002867
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002868 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002869#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002871 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2872 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2873 s_start = 0;
2874 s_end = 6;
2875 s_inc = 2;
2876 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002877
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002878 for (i = 0; i < row_info->width; i++)
2879 {
2880 png_byte v;
2881 int j;
2882
2883 v = (png_byte)((*sp >> sshift) & 0x03);
2884 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002885 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002886 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2887 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002888
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002889 if (dshift == s_end)
2890 {
2891 dshift = s_start;
2892 dp--;
2893 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002894
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002895 else
2896 dshift += s_inc;
2897 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002898
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002899 if (sshift == s_end)
2900 {
2901 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002902 sp--;
2903 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002904
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002905 else
2906 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002907 }
2908 break;
2909 }
2910 case 4:
2911 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002912 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2913 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002914 int sshift, dshift;
2915 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002916 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002917 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002918
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002919#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002920 if (transformations & PNG_PACKSWAP)
2921 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002922 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2923 dshift = (int)(((final_width + 1) & 0x01) << 2);
2924 s_start = 4;
2925 s_end = 0;
2926 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002927 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002928
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002929 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002930#endif
2931 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002932 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2933 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2934 s_start = 0;
2935 s_end = 4;
2936 s_inc = 4;
2937 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002938
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002939 for (i = 0; i < row_info->width; i++)
2940 {
2941 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2942 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002943
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002944 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002945 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002946 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2947 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002948
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002949 if (dshift == s_end)
2950 {
2951 dshift = s_start;
2952 dp--;
2953 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002954
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002955 else
2956 dshift += s_inc;
2957 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002958
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002959 if (sshift == s_end)
2960 {
2961 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002962 sp--;
2963 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002964
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002965 else
2966 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002967 }
2968 break;
2969 }
2970 default:
2971 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002972 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002973 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2974 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002975 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002976
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002977 int jstop = png_pass_inc[pass];
2978 png_uint_32 i;
2979
2980 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002981 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002982 png_byte v[8];
2983 int j;
2984
2985 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002986
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002987 for (j = 0; j < jstop; j++)
2988 {
2989 png_memcpy(dp, v, pixel_bytes);
2990 dp -= pixel_bytes;
2991 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002992
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002993 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002994 }
2995 break;
2996 }
2997 }
2998 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002999 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003000 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05003001#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003002 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05003003#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003004}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003005#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003006
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003007void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003008png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003009 png_const_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003010{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003011 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003012 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003013 switch (filter)
3014 {
3015 case PNG_FILTER_VALUE_NONE:
3016 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003017
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003018 case PNG_FILTER_VALUE_SUB:
3019 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003020 png_size_t i;
3021 png_size_t istop = row_info->rowbytes;
3022 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003023 png_bytep rp = row + bpp;
3024 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003025
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003026 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003027 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003028 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
3029 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003030 }
3031 break;
3032 }
3033 case PNG_FILTER_VALUE_UP:
3034 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003035 png_size_t i;
3036 png_size_t istop = row_info->rowbytes;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003037 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003038 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003039
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003040 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003041 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003042 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3043 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003044 }
3045 break;
3046 }
3047 case PNG_FILTER_VALUE_AVG:
3048 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003049 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003050 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003051 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003052 png_bytep lp = row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003053 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3054 png_size_t istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003055
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003056 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003057 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003058 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003059 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003060 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003061 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003062
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003063 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003064 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003065 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003066 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003067 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003068 }
3069 break;
3070 }
3071 case PNG_FILTER_VALUE_PAETH:
3072 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003073 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003074 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003075 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003076 png_bytep lp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003077 png_const_bytep cp = prev_row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003078 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3079 png_size_t istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003080
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003081 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003082 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003083 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3084 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003085 }
3086
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003087 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003088 {
3089 int a, b, c, pa, pb, pc, p;
3090
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003091 a = *lp++;
3092 b = *pp++;
3093 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003094
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003095 p = b - c;
3096 pc = a - c;
3097
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003098#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003099 pa = abs(p);
3100 pb = abs(pc);
3101 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003102#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003103 pa = p < 0 ? -p : p;
3104 pb = pc < 0 ? -pc : pc;
3105 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003106#endif
3107
3108 /*
3109 if (pa <= pb && pa <= pc)
3110 p = a;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003111
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003112 else if (pb <= pc)
3113 p = b;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003114
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003115 else
3116 p = c;
3117 */
3118
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003119 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003120
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003121 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3122 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003123 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003124 break;
3125 }
3126 default:
Glenn Randers-Pehrsona272d8f2010-06-25 21:45:31 -05003127 png_error(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05003128 /*NOT REACHED */
3129 break;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003130 }
3131}
Guy Schalnat0d580581995-07-20 02:43:20 -05003132
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003133#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003134void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003135png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003136{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003137#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003138 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003139
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003140 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003141 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003142
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003143 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003144 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003145
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003146 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003147 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003148
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003149 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003150 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3151#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003152
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003153 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003154 png_ptr->row_number++;
3155 if (png_ptr->row_number < png_ptr->num_rows)
3156 return;
3157
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003158#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003159 if (png_ptr->interlaced)
3160 {
3161 png_ptr->row_number = 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003162
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003163 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003164
Guy Schalnat0d580581995-07-20 02:43:20 -05003165 do
3166 {
3167 png_ptr->pass++;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003168
Guy Schalnat0d580581995-07-20 02:43:20 -05003169 if (png_ptr->pass >= 7)
3170 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003171
Guy Schalnat0d580581995-07-20 02:43:20 -05003172 png_ptr->iwidth = (png_ptr->width +
3173 png_pass_inc[png_ptr->pass] - 1 -
3174 png_pass_start[png_ptr->pass]) /
3175 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003176
Guy Schalnat0d580581995-07-20 02:43:20 -05003177 if (!(png_ptr->transformations & PNG_INTERLACE))
3178 {
3179 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003180 png_pass_yinc[png_ptr->pass] - 1 -
3181 png_pass_ystart[png_ptr->pass]) /
3182 png_pass_yinc[png_ptr->pass];
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003183
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 if (!(png_ptr->num_rows))
3185 continue;
3186 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003187
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003188 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003189 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003190 } while (png_ptr->iwidth == 0);
3191
3192 if (png_ptr->pass < 7)
3193 return;
3194 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003195#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003196
Guy Schalnate5a37791996-06-05 15:50:50 -05003197 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003198 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003199 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003200 char extra;
3201 int ret;
3202
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003203 png_ptr->zstream.next_out = (Byte *)&extra;
3204 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003205
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003206 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003207 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003208 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003209 {
3210 while (!png_ptr->idat_size)
3211 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003212 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003213
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003214 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003215
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003216 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003217 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003218 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003219 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003220
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003221 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003222 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003223
3224 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003225
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003226 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3227 png_ptr->zstream.next_in = png_ptr->zbuf;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003228
Guy Schalnat0d580581995-07-20 02:43:20 -05003229 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003230 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003231
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003232 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3233 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003234 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003235 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003236
Guy Schalnat0d580581995-07-20 02:43:20 -05003237 if (ret == Z_STREAM_END)
3238 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003239 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003240 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003241 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003242
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003243 png_ptr->mode |= PNG_AFTER_IDAT;
3244 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003245 break;
3246 }
3247 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003248 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003249 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003250
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003251 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003252 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003253 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003254 png_ptr->mode |= PNG_AFTER_IDAT;
3255 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3256 break;
3257 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003258
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003259 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003260 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003261 }
3262
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003263 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003264 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003265
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003266 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003267
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003268 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003269}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003270#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003271
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003272void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003273png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003274{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003275#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003276 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003277
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003278 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003279 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003280
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003281 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003282 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003283
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003284 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003285 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003286
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003287 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003288 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3289#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003290
Guy Schalnat0d580581995-07-20 02:43:20 -05003291 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003292 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003293
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003294 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003295 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003296 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003297#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003298 if (png_ptr->interlaced)
3299 {
3300 if (!(png_ptr->transformations & PNG_INTERLACE))
3301 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003302 png_pass_ystart[0]) / png_pass_yinc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05003303 else
3304 png_ptr->num_rows = png_ptr->height;
3305
3306 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003307 png_pass_inc[png_ptr->pass] - 1 -
3308 png_pass_start[png_ptr->pass]) /
3309 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003310 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003311
Guy Schalnat0d580581995-07-20 02:43:20 -05003312 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003313#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003314 {
3315 png_ptr->num_rows = png_ptr->height;
3316 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003317 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003318
Guy Schalnat0d580581995-07-20 02:43:20 -05003319 max_pixel_depth = png_ptr->pixel_depth;
3320
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003321#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003322 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003323 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003324#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003325
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003326#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003327 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003328 {
3329 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3330 {
3331 if (png_ptr->num_trans)
3332 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003333
Guy Schalnat0d580581995-07-20 02:43:20 -05003334 else
3335 max_pixel_depth = 24;
3336 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003337
Guy Schalnat0d580581995-07-20 02:43:20 -05003338 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3339 {
3340 if (max_pixel_depth < 8)
3341 max_pixel_depth = 8;
3342 if (png_ptr->num_trans)
3343 max_pixel_depth *= 2;
3344 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003345
Guy Schalnat0d580581995-07-20 02:43:20 -05003346 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3347 {
3348 if (png_ptr->num_trans)
3349 {
3350 max_pixel_depth *= 4;
3351 max_pixel_depth /= 3;
3352 }
3353 }
3354 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003355#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003356
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003357#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003358 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003359 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003360 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3361 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003362
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003363 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003364 {
3365 if (max_pixel_depth <= 8)
3366 max_pixel_depth = 16;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003367
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003368 else
3369 max_pixel_depth = 32;
3370 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003371
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003372 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3373 {
3374 if (max_pixel_depth <= 32)
3375 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003376
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003377 else
3378 max_pixel_depth = 64;
3379 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003380 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003381#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003382
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003383#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003384 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3385 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003386 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003387#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003388 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003389#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003390#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003391 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003392#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003393 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003394 {
3395 if (max_pixel_depth <= 16)
3396 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003397
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003398 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003399 max_pixel_depth = 64;
3400 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003401
Guy Schalnat0d580581995-07-20 02:43:20 -05003402 else
3403 {
3404 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003405 {
3406 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003407 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003408
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003409 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003410 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003411 }
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003412 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3413 max_pixel_depth = 64;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003414
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003415 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003416 max_pixel_depth = 48;
3417 }
3418 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003419#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003420
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003421#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3422defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003423 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003424 {
3425 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003426 png_ptr->user_transform_channels;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003427 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003428 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003429 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003430#endif
3431
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003432 /* Align the width on the next larger 8 pixels. Mainly used
3433 * for interlacing
3434 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003435 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003436 /* Calculate the maximum bytes needed, adding a byte and a pixel
3437 * for safety's sake
3438 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003439 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003440 1 + ((max_pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003441
Guy Schalnat0d580581995-07-20 02:43:20 -05003442#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003443 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003444 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003445#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003446
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003447 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003448 {
3449 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003450
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003451 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003452 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3453 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003454
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003455 else
3456 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3457 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003458
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003459 png_ptr->old_big_row_buf_size = row_bytes + 48;
3460
3461#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3462 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3463 * of padding before and after row_buf.
3464 */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003465 png_ptr->row_buf = png_ptr->big_row_buf + 32 -
3466 (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F);
3467
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003468 png_ptr->old_big_row_buf_size = row_bytes + 48;
3469#else
3470 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003471 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003472#endif
3473 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003474 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003475
3476#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003477 if (png_ptr->rowbytes > 65535)
Guy Schalnate5a37791996-06-05 15:50:50 -05003478 png_error(png_ptr, "This image requires a row greater than 64KB");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003479
Guy Schalnat0d580581995-07-20 02:43:20 -05003480#endif
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003481 if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003482 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003483
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003484 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003485 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003486 png_free(png_ptr, png_ptr->prev_row);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003487
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003488 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003489
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003490 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003491 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003492
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003493 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003494
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003495 png_debug1(3, "width = %u,", png_ptr->width);
3496 png_debug1(3, "height = %u,", png_ptr->height);
3497 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3498 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3499 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3500 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003501 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003502
Guy Schalnate5a37791996-06-05 15:50:50 -05003503 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003504}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003505
3506#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
3507int PNGAPI
3508png_get_num_passes(png_structp png_ptr)
3509{
3510 if (png_ptr != NULL)
3511 {
3512 if (png_ptr->interlaced)
3513 return 7;
3514 else
3515 return 1;
3516 }
3517
3518 /* Here on error */
3519 return 0;
3520}
3521
3522png_uint_32 PNGAPI
3523png_get_num_rows(png_structp png_ptr)
3524{
3525 if (png_ptr != NULL)
3526 {
3527 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003528 return png_ptr->num_rows;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003529 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003530 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3531 "before png_get_num_rows");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003532 }
3533
3534 /* Here on error */
3535 return 0;
3536}
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003537
3538png_uint_32 PNGAPI
3539png_get_num_cols(png_structp png_ptr)
3540{
3541 if (png_ptr != NULL)
3542 {
3543 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003544 return png_ptr->iwidth;
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003545 else
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003546 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3547 "before png_get_num_cols");
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003548 }
3549
3550 /* Here on error */
3551 return 0;
3552}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003553#endif /* SEQUENTIAL READ */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003554#endif /* PNG_READ_SUPPORTED */