blob: 66c7dff78cb705a40a2b1a2708f856549f18a84e [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-Pehrsonf197d6d2010-10-15 19:22:01 -05004 * Last changed in libpng 1.5.0 [(PENDING RELEASE)]
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-Pehrsonbc363ec2010-10-12 21:17:00 -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;
Glenn Randers-Pehrsonc1270572010-10-12 12:13:19 -05001214 png_uint_32 dl;
1215 png_size_t max_dl;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001216
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001217 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001218
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001219#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001220
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001221 if (png_ptr->user_chunk_cache_max != 0)
1222 {
1223 if (png_ptr->user_chunk_cache_max == 1)
1224 {
1225 png_crc_finish(png_ptr, length);
1226 return;
1227 }
1228 if (--png_ptr->user_chunk_cache_max == 1)
1229 {
1230 png_warning(png_ptr, "No space in chunk cache for sPLT");
1231 png_crc_finish(png_ptr, length);
1232 return;
1233 }
1234 }
1235#endif
1236
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001237 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1238 png_error(png_ptr, "Missing IHDR before sPLT");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001239
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001240 else if (png_ptr->mode & PNG_HAVE_IDAT)
1241 {
1242 png_warning(png_ptr, "Invalid sPLT after IDAT");
1243 png_crc_finish(png_ptr, length);
1244 return;
1245 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001246
1247#ifdef PNG_MAX_MALLOC_64K
1248 if (length > (png_uint_32)65535L)
1249 {
1250 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1251 skip = length - (png_uint_32)65535L;
1252 length = (png_uint_32)65535L;
1253 }
1254#endif
1255
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001256 png_free(png_ptr, png_ptr->chunkdata);
1257 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001258
1259 /* WARNING: this may break if size_t is less than 32 bits; it is assumed
1260 * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
1261 * potential breakage point if the types in pngconf.h aren't exactly right.
1262 */
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001263 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001264 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001265
1266 if (png_crc_finish(png_ptr, skip))
1267 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001268 png_free(png_ptr, png_ptr->chunkdata);
1269 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001270 return;
1271 }
1272
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001273 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001274
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001275 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1276 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001277 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001278
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001279 ++entry_start;
1280
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001281 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001282 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001283 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001284 png_free(png_ptr, png_ptr->chunkdata);
1285 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001286 png_warning(png_ptr, "malformed sPLT chunk");
1287 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001288 }
1289
1290 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001291 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001292 /* This must fit in a png_uint_32 because it is derived from the original
1293 * chunk data length (and use 'length', not 'slength' here for clarity -
1294 * they are guaranteed to be the same, see the tests above.)
1295 */
1296 data_length = length - (png_uint_32)(entry_start -
1297 (png_bytep)png_ptr->chunkdata);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001298
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001299 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001300 if (data_length % entry_size)
1301 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001302 png_free(png_ptr, png_ptr->chunkdata);
1303 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001304 png_warning(png_ptr, "sPLT chunk has bad length");
1305 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001306 }
1307
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -05001308 dl = (png_int_32)(data_length / entry_size);
Glenn Randers-Pehrsonc1270572010-10-12 12:13:19 -05001309 max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry);
1310
1311 if (dl > max_dl)
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001312 {
1313 png_warning(png_ptr, "sPLT chunk too long");
1314 return;
1315 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001316
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -05001317 new_palette.nentries = (png_int_32)(data_length / entry_size);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001318 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001319 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001320
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001321 if (new_palette.entries == NULL)
1322 {
1323 png_warning(png_ptr, "sPLT chunk requires too much memory");
1324 return;
1325 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001326
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001327#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001328 for (i = 0; i < new_palette.nentries; i++)
1329 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001330 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001331
1332 if (new_palette.depth == 8)
1333 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001334 pp->red = *entry_start++;
1335 pp->green = *entry_start++;
1336 pp->blue = *entry_start++;
1337 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001338 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001339
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001340 else
1341 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001342 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1343 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1344 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1345 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001346 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001347
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001348 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1349 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001350#else
1351 pp = new_palette.entries;
1352 for (i = 0; i < new_palette.nentries; i++)
1353 {
1354
1355 if (new_palette.depth == 8)
1356 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001357 pp[i].red = *entry_start++;
1358 pp[i].green = *entry_start++;
1359 pp[i].blue = *entry_start++;
1360 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001361 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001362
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001363 else
1364 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001365 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1366 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1367 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1368 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001369 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001370
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001371 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1372 }
1373#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001374
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001375 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001376 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001377
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001378 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001379
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001380 png_free(png_ptr, png_ptr->chunkdata);
1381 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001382 png_free(png_ptr, new_palette.entries);
1383}
1384#endif /* PNG_READ_sPLT_SUPPORTED */
1385
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001386#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001387void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001388png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001389{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001390 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001391
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001392 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001393
Guy Schalnate5a37791996-06-05 15:50:50 -05001394 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1395 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001396 else if (png_ptr->mode & PNG_HAVE_IDAT)
1397 {
1398 png_warning(png_ptr, "Invalid tRNS after IDAT");
1399 png_crc_finish(png_ptr, length);
1400 return;
1401 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001402
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001403 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001404 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001405 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001406 png_crc_finish(png_ptr, length);
1407 return;
1408 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001409
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001410 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001411 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001412 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001413
1414 if (length != 2)
1415 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001416 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001417 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001418 return;
1419 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001420
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001421 png_crc_read(png_ptr, buf, 2);
1422 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001423 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001424 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001425
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001426 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1427 {
1428 png_byte buf[6];
1429
1430 if (length != 6)
1431 {
1432 png_warning(png_ptr, "Incorrect tRNS chunk length");
1433 png_crc_finish(png_ptr, length);
1434 return;
1435 }
1436 png_crc_read(png_ptr, buf, (png_size_t)length);
1437 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001438 png_ptr->trans_color.red = png_get_uint_16(buf);
1439 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1440 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001441 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001442
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001443 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1444 {
1445 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1446 {
1447 /* Should be an error, but we can cope with it. */
1448 png_warning(png_ptr, "Missing PLTE before tRNS");
1449 }
1450 if (length > (png_uint_32)png_ptr->num_palette ||
1451 length > PNG_MAX_PALETTE_LENGTH)
1452 {
1453 png_warning(png_ptr, "Incorrect tRNS chunk length");
1454 png_crc_finish(png_ptr, length);
1455 return;
1456 }
1457 if (length == 0)
1458 {
1459 png_warning(png_ptr, "Zero length tRNS chunk");
1460 png_crc_finish(png_ptr, length);
1461 return;
1462 }
1463 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1464 png_ptr->num_trans = (png_uint_16)length;
1465 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001466
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001467 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001468 {
1469 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001470 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001471 return;
1472 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001473
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001474 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001475 {
1476 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001477 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001478 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001479
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001480 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001481 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001482}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001483#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001484
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001485#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001486void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001487png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001488{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001489 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001490 png_byte buf[6];
1491
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001492 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001493
Guy Schalnate5a37791996-06-05 15:50:50 -05001494 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1495 png_error(png_ptr, "Missing IHDR before bKGD");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001496
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001497 else if (png_ptr->mode & PNG_HAVE_IDAT)
1498 {
1499 png_warning(png_ptr, "Invalid bKGD after IDAT");
1500 png_crc_finish(png_ptr, length);
1501 return;
1502 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001503
Guy Schalnate5a37791996-06-05 15:50:50 -05001504 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001505 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001506 {
1507 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001508 png_crc_finish(png_ptr, length);
1509 return;
1510 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001511
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001512 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001513 {
1514 png_warning(png_ptr, "Duplicate bKGD chunk");
1515 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001516 return;
1517 }
1518
Guy Schalnat0d580581995-07-20 02:43:20 -05001519 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1520 truelen = 1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001521
Guy Schalnat0d580581995-07-20 02:43:20 -05001522 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1523 truelen = 6;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001524
Guy Schalnat0d580581995-07-20 02:43:20 -05001525 else
1526 truelen = 2;
1527
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001528 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001529 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001530 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001531 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001532 return;
1533 }
1534
Andreas Dilger47a0c421997-05-16 02:46:07 -05001535 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001536
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001537 if (png_crc_finish(png_ptr, 0))
1538 return;
1539
Guy Schalnate5a37791996-06-05 15:50:50 -05001540 /* We convert the index value into RGB components so that we can allow
1541 * arbitrary RGB values for background when we have transparency, and
1542 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001543 * from the info_ptr struct.
1544 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001545 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001546 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001547 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001548 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001549 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001550 if (buf[0] >= info_ptr->num_palette)
1551 {
1552 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1553 return;
1554 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001555
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001556 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001557 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001558
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001559 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001560 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001561
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001562 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001563 (png_uint_16)png_ptr->palette[buf[0]].blue;
1564 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001565 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001566
Andreas Dilger47a0c421997-05-16 02:46:07 -05001567 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001568 {
1569 png_ptr->background.red =
1570 png_ptr->background.green =
1571 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001572 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001573 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001574
Guy Schalnat0d580581995-07-20 02:43:20 -05001575 else
1576 {
1577 png_ptr->background.red = png_get_uint_16(buf);
1578 png_ptr->background.green = png_get_uint_16(buf + 2);
1579 png_ptr->background.blue = png_get_uint_16(buf + 4);
1580 }
1581
Andreas Dilger47a0c421997-05-16 02:46:07 -05001582 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001583}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001584#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001585
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001586#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001587void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001588png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001589{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001590 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001591 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001592
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001593 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001594
Guy Schalnate5a37791996-06-05 15:50:50 -05001595 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1596 png_error(png_ptr, "Missing IHDR before hIST");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001597
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001598 else if (png_ptr->mode & PNG_HAVE_IDAT)
1599 {
1600 png_warning(png_ptr, "Invalid hIST after IDAT");
1601 png_crc_finish(png_ptr, length);
1602 return;
1603 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001604
Guy Schalnate5a37791996-06-05 15:50:50 -05001605 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1606 {
1607 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001608 png_crc_finish(png_ptr, length);
1609 return;
1610 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001611
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001612 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001613 {
1614 png_warning(png_ptr, "Duplicate hIST chunk");
1615 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001616 return;
1617 }
1618
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001619 num = length / 2 ;
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -05001620 if (num != (unsigned int)png_ptr->num_palette || num >
1621 (unsigned int)PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001622 {
1623 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001624 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001625 return;
1626 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001627
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001628 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001629 {
1630 png_byte buf[2];
1631
1632 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001633 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001634 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001635
1636 if (png_crc_finish(png_ptr, 0))
1637 return;
1638
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001639 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001640}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001641#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001642
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001643#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001644void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001645png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001646{
1647 png_byte buf[9];
1648 png_uint_32 res_x, res_y;
1649 int unit_type;
1650
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001651 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001652
Guy Schalnate5a37791996-06-05 15:50:50 -05001653 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001654 png_error(png_ptr, "Missing IHDR before pHYs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001655
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001656 else if (png_ptr->mode & PNG_HAVE_IDAT)
1657 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001658 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001659 png_crc_finish(png_ptr, length);
1660 return;
1661 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001662
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001663 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001664 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001665 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001666 png_crc_finish(png_ptr, length);
1667 return;
1668 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001669
Guy Schalnat0d580581995-07-20 02:43:20 -05001670 if (length != 9)
1671 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001672 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001673 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001674 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001675 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001676
1677 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001678
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001679 if (png_crc_finish(png_ptr, 0))
1680 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001681
1682 res_x = png_get_uint_32(buf);
1683 res_y = png_get_uint_32(buf + 4);
1684 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001685 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001686}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001687#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001688
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001689#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001690void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001691png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001692{
1693 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001694 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001695 int unit_type;
1696
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001697 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001698
Guy Schalnate5a37791996-06-05 15:50:50 -05001699 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1700 png_error(png_ptr, "Missing IHDR before oFFs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001701
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001702 else if (png_ptr->mode & PNG_HAVE_IDAT)
1703 {
1704 png_warning(png_ptr, "Invalid oFFs after IDAT");
1705 png_crc_finish(png_ptr, length);
1706 return;
1707 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001708
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001709 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001710 {
1711 png_warning(png_ptr, "Duplicate oFFs chunk");
1712 png_crc_finish(png_ptr, length);
1713 return;
1714 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001715
Guy Schalnat0d580581995-07-20 02:43:20 -05001716 if (length != 9)
1717 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001718 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001719 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001720 return;
1721 }
1722
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001723 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001724
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001725 if (png_crc_finish(png_ptr, 0))
1726 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001727
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001728 offset_x = png_get_int_32(buf);
1729 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001730 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001731 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1732}
1733#endif
1734
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001735#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001736/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001737void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001738png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1739{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001740 png_int_32 X0, X1;
1741 png_byte type, nparams;
1742 png_charp buf, units, endptr;
1743 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001744 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001745 int i;
1746
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001747 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001748
1749 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1750 png_error(png_ptr, "Missing IHDR before pCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001751
Andreas Dilger47a0c421997-05-16 02:46:07 -05001752 else if (png_ptr->mode & PNG_HAVE_IDAT)
1753 {
1754 png_warning(png_ptr, "Invalid pCAL after IDAT");
1755 png_crc_finish(png_ptr, length);
1756 return;
1757 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001758
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001759 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001760 {
1761 png_warning(png_ptr, "Duplicate pCAL chunk");
1762 png_crc_finish(png_ptr, length);
1763 return;
1764 }
1765
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001766 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001767 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001768 png_free(png_ptr, png_ptr->chunkdata);
1769 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001770
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001771 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001772 {
1773 png_warning(png_ptr, "No memory for pCAL purpose");
1774 return;
1775 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001776
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001777 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001778 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001779
1780 if (png_crc_finish(png_ptr, 0))
1781 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001782 png_free(png_ptr, png_ptr->chunkdata);
1783 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001784 return;
1785 }
1786
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001787 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001788
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001789 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001790 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001791 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001792
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001793 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001794
1795 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001796 * in order to get the parameter information.
1797 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001798 if (endptr <= buf + 12)
1799 {
1800 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001801 png_free(png_ptr, png_ptr->chunkdata);
1802 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001803 return;
1804 }
1805
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001806 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001807 X0 = png_get_int_32((png_bytep)buf+1);
1808 X1 = png_get_int_32((png_bytep)buf+5);
1809 type = buf[9];
1810 nparams = buf[10];
1811 units = buf + 11;
1812
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001813 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001814 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001815 * equation types.
1816 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001817 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1818 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1819 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1820 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1821 {
1822 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001823 png_free(png_ptr, png_ptr->chunkdata);
1824 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001825 return;
1826 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001827
Andreas Dilger47a0c421997-05-16 02:46:07 -05001828 else if (type >= PNG_EQUATION_LAST)
1829 {
1830 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1831 }
1832
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001833 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001834 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001835
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001836 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001837 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001838 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001839 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001840 {
1841 png_free(png_ptr, png_ptr->chunkdata);
1842 png_ptr->chunkdata = NULL;
1843 png_warning(png_ptr, "No memory for pCAL params");
1844 return;
1845 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001846
1847 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001848 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001849 {
1850 buf++; /* Skip the null string terminator from previous parameter. */
1851
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001852 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001853 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001854 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001855
1856 /* Make sure we haven't run out of data yet */
1857 if (buf > endptr)
1858 {
1859 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001860 png_free(png_ptr, png_ptr->chunkdata);
1861 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001862 png_free(png_ptr, params);
1863 return;
1864 }
1865 }
1866
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001867 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001868 units, params);
1869
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001870 png_free(png_ptr, png_ptr->chunkdata);
1871 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001872 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001873}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001874#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001875
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001876#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001877/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001878void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001879png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1880{
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001881 png_size_t slength, index;
1882 int state;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001883
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001884 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001885
1886 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1887 png_error(png_ptr, "Missing IHDR before sCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001888
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001889 else if (png_ptr->mode & PNG_HAVE_IDAT)
1890 {
1891 png_warning(png_ptr, "Invalid sCAL after IDAT");
1892 png_crc_finish(png_ptr, length);
1893 return;
1894 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001895
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001896 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001897 {
1898 png_warning(png_ptr, "Duplicate sCAL chunk");
1899 png_crc_finish(png_ptr, length);
1900 return;
1901 }
1902
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001903 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001904 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001905 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001906
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001907 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001908 {
1909 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05001910 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001911 return;
1912 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001913
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001914 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001915 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001916 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001917
1918 if (png_crc_finish(png_ptr, 0))
1919 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001920 png_free(png_ptr, png_ptr->chunkdata);
1921 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001922 return;
1923 }
1924
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001925 /* Validate the unit. */
1926 if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001927 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001928 png_warning(png_ptr, "Invalid sCAL ignored: invalid unit");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05001929 png_free(png_ptr, png_ptr->chunkdata);
1930 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001931 return;
1932 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001933
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001934 /* Validate the ASCII numbers, need two ASCII numbers separated by
1935 * a '\0' and they need to fit exactly in the chunk data.
1936 */
1937 index = 0;
1938 state = 0;
1939 if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
1940 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
1941 index >= slength || png_ptr->chunkdata[index++] != 0)
1942 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
1943 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001944 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001945 png_size_t heighti = index;
1946 if (png_ptr->chunkdata[index] == 45 /* negative height */ ||
1947 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001948 index != slength)
1949 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001950 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001951 /* This is the (only) success case. */
1952 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
1953 png_ptr->chunkdata+1, png_ptr->chunkdata+heighti);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001954 }
1955
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001956 /* Clean up - just free the temporarily allocated buffer. */
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001957 png_free(png_ptr, png_ptr->chunkdata);
1958 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001959}
1960#endif
1961
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001962#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001963void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001964png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001965{
1966 png_byte buf[7];
1967 png_time mod_time;
1968
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001969 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001970
Guy Schalnate5a37791996-06-05 15:50:50 -05001971 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001972 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001973
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001974 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001975 {
1976 png_warning(png_ptr, "Duplicate tIME chunk");
1977 png_crc_finish(png_ptr, length);
1978 return;
1979 }
1980
1981 if (png_ptr->mode & PNG_HAVE_IDAT)
1982 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001983
Guy Schalnat0d580581995-07-20 02:43:20 -05001984 if (length != 7)
1985 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001986 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001987 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001988 return;
1989 }
1990
1991 png_crc_read(png_ptr, buf, 7);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001992
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001993 if (png_crc_finish(png_ptr, 0))
1994 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001995
1996 mod_time.second = buf[6];
1997 mod_time.minute = buf[5];
1998 mod_time.hour = buf[4];
1999 mod_time.day = buf[3];
2000 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002001 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05002002
Andreas Dilger47a0c421997-05-16 02:46:07 -05002003 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05002004}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002005#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002006
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002007#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002008/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002009void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002010png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002011{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002012 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002013 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06002014 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002015 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002016 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002017 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002018
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002019 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05002020
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002021#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002022 if (png_ptr->user_chunk_cache_max != 0)
2023 {
2024 if (png_ptr->user_chunk_cache_max == 1)
2025 {
2026 png_crc_finish(png_ptr, length);
2027 return;
2028 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002029
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002030 if (--png_ptr->user_chunk_cache_max == 1)
2031 {
2032 png_warning(png_ptr, "No space in chunk cache for tEXt");
2033 png_crc_finish(png_ptr, length);
2034 return;
2035 }
2036 }
2037#endif
2038
Guy Schalnate5a37791996-06-05 15:50:50 -05002039 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2040 png_error(png_ptr, "Missing IHDR before tEXt");
2041
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002042 if (png_ptr->mode & PNG_HAVE_IDAT)
2043 png_ptr->mode |= PNG_AFTER_IDAT;
2044
Andreas Dilger47a0c421997-05-16 02:46:07 -05002045#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002046 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002047 {
2048 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002049 skip = length - (png_uint_32)65535L;
2050 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002051 }
2052#endif
2053
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002054 png_free(png_ptr, png_ptr->chunkdata);
2055
2056 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2057 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002058 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002059 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002060 return;
2061 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002062 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002063 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002064
2065 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002066 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002067 png_free(png_ptr, png_ptr->chunkdata);
2068 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002069 return;
2070 }
2071
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002072 key = png_ptr->chunkdata;
2073
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002074 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002075
2076 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002077 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002078
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002079 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002080 text++;
2081
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002082 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002083 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002084
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002085 if (text_ptr == NULL)
2086 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002087 png_warning(png_ptr, "Not enough memory to process text chunk");
2088 png_free(png_ptr, png_ptr->chunkdata);
2089 png_ptr->chunkdata = NULL;
2090 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002091 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002092
Andreas Dilger47a0c421997-05-16 02:46:07 -05002093 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2094 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002095 text_ptr->lang = NULL;
2096 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002097 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002098 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002099 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002100
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002101 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002102
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002103 png_free(png_ptr, png_ptr->chunkdata);
2104 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002105 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002106
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002107 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002108 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002109}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002110#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002111
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002112#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002113/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002114void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002115png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002116{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002117 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002118 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002119 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002120 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002121 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002122
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002123 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002124
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002125#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002126 if (png_ptr->user_chunk_cache_max != 0)
2127 {
2128 if (png_ptr->user_chunk_cache_max == 1)
2129 {
2130 png_crc_finish(png_ptr, length);
2131 return;
2132 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002133
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002134 if (--png_ptr->user_chunk_cache_max == 1)
2135 {
2136 png_warning(png_ptr, "No space in chunk cache for zTXt");
2137 png_crc_finish(png_ptr, length);
2138 return;
2139 }
2140 }
2141#endif
2142
Guy Schalnate5a37791996-06-05 15:50:50 -05002143 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2144 png_error(png_ptr, "Missing IHDR before zTXt");
2145
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002146 if (png_ptr->mode & PNG_HAVE_IDAT)
2147 png_ptr->mode |= PNG_AFTER_IDAT;
2148
Andreas Dilger47a0c421997-05-16 02:46:07 -05002149#ifdef PNG_MAX_MALLOC_64K
2150 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002151 * there is no hard and fast rule to tell us where to stop.
2152 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002153 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002154 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002155 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2156 png_crc_finish(png_ptr, length);
2157 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002158 }
2159#endif
2160
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002161 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002162 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2163 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002164 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002165 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2166 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002167 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002168
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002169 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002170 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002171
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002172 if (png_crc_finish(png_ptr, 0))
2173 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002174 png_free(png_ptr, png_ptr->chunkdata);
2175 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002176 return;
2177 }
2178
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002179 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002180
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002181 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002182 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002183
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002184 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002185 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002186 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002187 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002188 png_free(png_ptr, png_ptr->chunkdata);
2189 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002190 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002191 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002192
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002193 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002194 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002195 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002196 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2197 {
2198 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2199 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2200 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002201 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002202 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002203
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002204 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002205
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002206 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002207 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002208
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002209 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002210 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002211
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002212 if (text_ptr == NULL)
2213 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002214 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2215 png_free(png_ptr, png_ptr->chunkdata);
2216 png_ptr->chunkdata = NULL;
2217 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002218 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002219
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002220 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002221 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002222 text_ptr->lang = NULL;
2223 text_ptr->lang_key = NULL;
2224 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002225 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002226 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002227
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002228 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002229
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002230 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002231 png_free(png_ptr, png_ptr->chunkdata);
2232 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002233
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002234 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002235 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002236}
2237#endif
2238
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002239#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002240/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002241void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002242png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2243{
2244 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002245 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002246 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002247 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002248 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002249 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002250
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002251 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002252
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002253#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002254 if (png_ptr->user_chunk_cache_max != 0)
2255 {
2256 if (png_ptr->user_chunk_cache_max == 1)
2257 {
2258 png_crc_finish(png_ptr, length);
2259 return;
2260 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002261
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002262 if (--png_ptr->user_chunk_cache_max == 1)
2263 {
2264 png_warning(png_ptr, "No space in chunk cache for iTXt");
2265 png_crc_finish(png_ptr, length);
2266 return;
2267 }
2268 }
2269#endif
2270
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002271 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2272 png_error(png_ptr, "Missing IHDR before iTXt");
2273
2274 if (png_ptr->mode & PNG_HAVE_IDAT)
2275 png_ptr->mode |= PNG_AFTER_IDAT;
2276
2277#ifdef PNG_MAX_MALLOC_64K
2278 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002279 * there is no hard and fast rule to tell us where to stop.
2280 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002281 if (length > (png_uint_32)65535L)
2282 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002283 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2284 png_crc_finish(png_ptr, length);
2285 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002286 }
2287#endif
2288
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002289 png_free(png_ptr, png_ptr->chunkdata);
2290 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2291 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002292 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002293 png_warning(png_ptr, "No memory to process iTXt chunk");
2294 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002295 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002296 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002297 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002298
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002299 if (png_crc_finish(png_ptr, 0))
2300 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002301 png_free(png_ptr, png_ptr->chunkdata);
2302 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002303 return;
2304 }
2305
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002306 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002307
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002308 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002309 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002310
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002311 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002312
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002313 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002314 * translated keyword (possibly empty), and possibly some text after the
2315 * keyword
2316 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002317
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002318 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002319 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002320 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002321 png_free(png_ptr, png_ptr->chunkdata);
2322 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002323 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002324 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002325
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002326 else
2327 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002328 comp_flag = *lang++;
2329 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002330 }
2331
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002332 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002333 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002334
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002335 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002336
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002337 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002338 {
2339 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002340 png_free(png_ptr, png_ptr->chunkdata);
2341 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002342 return;
2343 }
2344
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002345 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002346 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002347
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002348 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002349
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002350 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002351 {
2352 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002353 png_free(png_ptr, png_ptr->chunkdata);
2354 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002355 return;
2356 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002357
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002358 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002359
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002360 key=png_ptr->chunkdata;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002361
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002362 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002363 png_decompress_chunk(png_ptr, comp_type,
2364 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002365
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002366 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002367 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002368
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002369 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002370 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002371
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002372 if (text_ptr == NULL)
2373 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002374 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2375 png_free(png_ptr, png_ptr->chunkdata);
2376 png_ptr->chunkdata = NULL;
2377 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002378 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002379
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002380 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002381 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2382 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002383 text_ptr->itxt_length = data_len;
2384 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002385 text_ptr->key = png_ptr->chunkdata;
2386 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002387
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002388 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002389
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002390 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002391 png_free(png_ptr, png_ptr->chunkdata);
2392 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002393
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002394 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002395 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002396}
2397#endif
2398
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002399/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002400 * chunk. If there isn't a problem with the chunk itself (ie bad
2401 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2402 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2403 * case it will be saved away to be written out later.
2404 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002405void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002406png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2407{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002408 png_uint_32 skip = 0;
2409
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002410 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002411
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002412#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002413 if (png_ptr->user_chunk_cache_max != 0)
2414 {
2415 if (png_ptr->user_chunk_cache_max == 1)
2416 {
2417 png_crc_finish(png_ptr, length);
2418 return;
2419 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002420
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002421 if (--png_ptr->user_chunk_cache_max == 1)
2422 {
2423 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2424 png_crc_finish(png_ptr, length);
2425 return;
2426 }
2427 }
2428#endif
2429
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002430 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002431 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002432 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002433 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002434 png_ptr->mode |= PNG_AFTER_IDAT;
2435 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002436
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002437 if (!(png_ptr->chunk_name[0] & 0x20))
2438 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002439#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002440 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002441 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002442#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002443 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002444#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002445 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002446#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002447 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002448 }
2449
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002450#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002451 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002452#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002453 || (png_ptr->read_user_chunk_fn != NULL)
2454#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002455 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002456 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002457#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002458 if (length > (png_uint_32)65535L)
2459 {
2460 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2461 skip = length - (png_uint_32)65535L;
2462 length = (png_uint_32)65535L;
2463 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002464#endif
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002465
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002466 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2467 (png_charp)png_ptr->chunk_name,
2468 png_sizeof(png_ptr->unknown_chunk.name));
2469 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2470 = '\0';
2471 png_ptr->unknown_chunk.size = (png_size_t)length;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002472
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002473 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002474 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002475
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002476 else
2477 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002478 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2479 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002480 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002481
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002482#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002483 if (png_ptr->read_user_chunk_fn != NULL)
2484 {
2485 /* Callback to user unknown chunk handler */
2486 int ret;
2487 ret = (*(png_ptr->read_user_chunk_fn))
2488 (png_ptr, &png_ptr->unknown_chunk);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002489
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002490 if (ret < 0)
2491 png_chunk_error(png_ptr, "error in user chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002492
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002493 if (ret == 0)
2494 {
2495 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002496#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002497 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2498 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002499#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002500 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002501
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002502 png_set_unknown_chunks(png_ptr, info_ptr,
2503 &png_ptr->unknown_chunk, 1);
2504 }
2505 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002506
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002507 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002508#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002509 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002510
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002511 png_free(png_ptr, png_ptr->unknown_chunk.data);
2512 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002513 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002514
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002515 else
2516#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002517 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002518
2519 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002520
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002521#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002522 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002523#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002524}
2525
2526/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002527 * This function can't have the "critical chunk check" incorporated
2528 * into it, since in the future we will need to be able to call user
2529 * functions to handle unknown critical chunks after we check that
2530 * the chunk name itself is valid.
2531 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002532
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002533#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002534
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002535void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002536png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002537{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002538 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002539 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002540 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002541 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002542 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002543 }
2544}
2545
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002546/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002547 * row. This routine takes care of alpha and transparency if requested.
2548 * This routine also handles the two methods of progressive display
2549 * of interlaced images, depending on the mask value.
2550 * The mask value describes which pixels are to be combined with
2551 * the row. The pattern always repeats every 8 pixels, so just 8
2552 * bits are needed. A one indicates the pixel is to be combined,
2553 * a zero indicates the pixel is to be skipped. This is in addition
2554 * to any alpha or transparency value associated with the pixel. If
2555 * you want all pixels to be combined, pass 0xff (255) in mask.
2556 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002557
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002558void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002559png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002560{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002561 png_debug(1, "in png_combine_row");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002562
Guy Schalnat0d580581995-07-20 02:43:20 -05002563 if (mask == 0xff)
2564 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002565 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002566 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002567 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002568
Guy Schalnat0d580581995-07-20 02:43:20 -05002569 else
2570 {
2571 switch (png_ptr->row_info.pixel_depth)
2572 {
2573 case 1:
2574 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002575 png_bytep sp = png_ptr->row_buf + 1;
2576 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002577 int s_inc, s_start, s_end;
2578 int m = 0x80;
2579 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002580 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002581 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002582
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002583#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002584 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002585 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002586 s_start = 0;
2587 s_end = 7;
2588 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002589 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002590
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002591 else
2592#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002593 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002594 s_start = 7;
2595 s_end = 0;
2596 s_inc = -1;
2597 }
2598
2599 shift = s_start;
2600
2601 for (i = 0; i < row_width; i++)
2602 {
2603 if (m & mask)
2604 {
2605 int value;
2606
2607 value = (*sp >> shift) & 0x01;
2608 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2609 *dp |= (png_byte)(value << shift);
2610 }
2611
2612 if (shift == s_end)
2613 {
2614 shift = s_start;
2615 sp++;
2616 dp++;
2617 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002618
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002619 else
2620 shift += s_inc;
2621
2622 if (m == 1)
2623 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002624
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002625 else
2626 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002627 }
2628 break;
2629 }
2630 case 2:
2631 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002632 png_bytep sp = png_ptr->row_buf + 1;
2633 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002634 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002635 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002636 int shift;
2637 png_uint_32 i;
2638 png_uint_32 row_width = png_ptr->width;
2639 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002640
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002641#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002642 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002643 {
2644 s_start = 0;
2645 s_end = 6;
2646 s_inc = 2;
2647 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002648
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002649 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002650#endif
2651 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002652 s_start = 6;
2653 s_end = 0;
2654 s_inc = -2;
2655 }
2656
2657 shift = s_start;
2658
2659 for (i = 0; i < row_width; i++)
2660 {
2661 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002662 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002663 value = (*sp >> shift) & 0x03;
2664 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2665 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002666 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002667
2668 if (shift == s_end)
2669 {
2670 shift = s_start;
2671 sp++;
2672 dp++;
2673 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002674
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002675 else
2676 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002677
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002678 if (m == 1)
2679 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002680
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002681 else
2682 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002683 }
2684 break;
2685 }
2686 case 4:
2687 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002688 png_bytep sp = png_ptr->row_buf + 1;
2689 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002690 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002691 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002692 int shift;
2693 png_uint_32 i;
2694 png_uint_32 row_width = png_ptr->width;
2695 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002696
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002697#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002698 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002699 {
2700 s_start = 0;
2701 s_end = 4;
2702 s_inc = 4;
2703 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002704
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002705 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002706#endif
2707 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002708 s_start = 4;
2709 s_end = 0;
2710 s_inc = -4;
2711 }
2712 shift = s_start;
2713
2714 for (i = 0; i < row_width; i++)
2715 {
2716 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002717 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002718 value = (*sp >> shift) & 0xf;
2719 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2720 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002721 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002722
2723 if (shift == s_end)
2724 {
2725 shift = s_start;
2726 sp++;
2727 dp++;
2728 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002729
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002730 else
2731 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002732
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002733 if (m == 1)
2734 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002735
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002736 else
2737 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002738 }
2739 break;
2740 }
2741 default:
2742 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002743 png_bytep sp = png_ptr->row_buf + 1;
2744 png_bytep dp = row;
2745 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2746 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002747 png_uint_32 row_width = png_ptr->width;
2748 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002749
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002750
2751 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002752 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002753 if (m & mask)
2754 {
2755 png_memcpy(dp, sp, pixel_bytes);
2756 }
2757
2758 sp += pixel_bytes;
2759 dp += pixel_bytes;
2760
2761 if (m == 1)
2762 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002763
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002764 else
2765 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002766 }
2767 break;
2768 }
2769 }
2770 }
2771}
2772
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002773#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002774void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002775png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002776{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002777 png_row_infop row_info = &(png_ptr->row_info);
2778 png_bytep row = png_ptr->row_buf + 1;
2779 int pass = png_ptr->pass;
2780 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002781 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2782 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002783 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002784
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002785 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002786 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002787 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002788 png_uint_32 final_width;
2789
2790 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002791
2792 switch (row_info->pixel_depth)
2793 {
2794 case 1:
2795 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002796 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2797 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002798 int sshift, dshift;
2799 int s_start, s_end, s_inc;
2800 int jstop = png_pass_inc[pass];
2801 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002802 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002803 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002804
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002805#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002806 if (transformations & PNG_PACKSWAP)
2807 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002808 sshift = (int)((row_info->width + 7) & 0x07);
2809 dshift = (int)((final_width + 7) & 0x07);
2810 s_start = 7;
2811 s_end = 0;
2812 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002813 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002814
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002815 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002816#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002817 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002818 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2819 dshift = 7 - (int)((final_width + 7) & 0x07);
2820 s_start = 0;
2821 s_end = 7;
2822 s_inc = 1;
2823 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002824
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002825 for (i = 0; i < row_info->width; i++)
2826 {
2827 v = (png_byte)((*sp >> sshift) & 0x01);
2828 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002829 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002830 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2831 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002832
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002833 if (dshift == s_end)
2834 {
2835 dshift = s_start;
2836 dp--;
2837 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002838
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002839 else
2840 dshift += s_inc;
2841 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002842
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002843 if (sshift == s_end)
2844 {
2845 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002846 sp--;
2847 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002848
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002849 else
2850 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002851 }
2852 break;
2853 }
2854 case 2:
2855 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002856 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2857 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2858 int sshift, dshift;
2859 int s_start, s_end, s_inc;
2860 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002861 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002862
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002863#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002864 if (transformations & PNG_PACKSWAP)
2865 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002866 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2867 dshift = (int)(((final_width + 3) & 0x03) << 1);
2868 s_start = 6;
2869 s_end = 0;
2870 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002871 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002872
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002873 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002874#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002875 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002876 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2877 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2878 s_start = 0;
2879 s_end = 6;
2880 s_inc = 2;
2881 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002882
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002883 for (i = 0; i < row_info->width; i++)
2884 {
2885 png_byte v;
2886 int j;
2887
2888 v = (png_byte)((*sp >> sshift) & 0x03);
2889 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002890 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002891 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2892 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002893
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002894 if (dshift == s_end)
2895 {
2896 dshift = s_start;
2897 dp--;
2898 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002899
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002900 else
2901 dshift += s_inc;
2902 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002903
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002904 if (sshift == s_end)
2905 {
2906 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002907 sp--;
2908 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002909
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002910 else
2911 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002912 }
2913 break;
2914 }
2915 case 4:
2916 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002917 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2918 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002919 int sshift, dshift;
2920 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002921 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002922 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002923
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002924#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002925 if (transformations & PNG_PACKSWAP)
2926 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002927 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2928 dshift = (int)(((final_width + 1) & 0x01) << 2);
2929 s_start = 4;
2930 s_end = 0;
2931 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002932 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002933
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002934 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002935#endif
2936 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002937 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2938 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2939 s_start = 0;
2940 s_end = 4;
2941 s_inc = 4;
2942 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002943
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002944 for (i = 0; i < row_info->width; i++)
2945 {
2946 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2947 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002948
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002949 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002950 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002951 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2952 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002953
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002954 if (dshift == s_end)
2955 {
2956 dshift = s_start;
2957 dp--;
2958 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002959
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002960 else
2961 dshift += s_inc;
2962 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002963
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002964 if (sshift == s_end)
2965 {
2966 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002967 sp--;
2968 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002969
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002970 else
2971 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002972 }
2973 break;
2974 }
2975 default:
2976 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002977 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002978 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2979 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002980 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002981
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002982 int jstop = png_pass_inc[pass];
2983 png_uint_32 i;
2984
2985 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002986 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002987 png_byte v[8];
2988 int j;
2989
2990 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002991
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002992 for (j = 0; j < jstop; j++)
2993 {
2994 png_memcpy(dp, v, pixel_bytes);
2995 dp -= pixel_bytes;
2996 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002997
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002998 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002999 }
3000 break;
3001 }
3002 }
3003 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003004 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003005 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05003006#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003007 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05003008#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003009}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003010#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003011
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003012void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003013png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003014 png_const_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003015{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003016 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003017 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003018 switch (filter)
3019 {
3020 case PNG_FILTER_VALUE_NONE:
3021 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003022
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003023 case PNG_FILTER_VALUE_SUB:
3024 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003025 png_size_t i;
3026 png_size_t istop = row_info->rowbytes;
3027 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003028 png_bytep rp = row + bpp;
3029 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003030
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003031 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003032 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003033 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
3034 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003035 }
3036 break;
3037 }
3038 case PNG_FILTER_VALUE_UP:
3039 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003040 png_size_t i;
3041 png_size_t istop = row_info->rowbytes;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003042 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003043 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003044
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003045 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003046 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003047 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3048 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003049 }
3050 break;
3051 }
3052 case PNG_FILTER_VALUE_AVG:
3053 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003054 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003055 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003056 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003057 png_bytep lp = row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003058 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3059 png_size_t istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003060
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003061 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003062 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003063 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003064 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003065 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003066 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003067
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003068 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003069 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003070 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003071 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003072 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003073 }
3074 break;
3075 }
3076 case PNG_FILTER_VALUE_PAETH:
3077 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003078 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003079 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003080 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003081 png_bytep lp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003082 png_const_bytep cp = prev_row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003083 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3084 png_size_t istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003085
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003086 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003087 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003088 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3089 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003090 }
3091
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003092 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003093 {
3094 int a, b, c, pa, pb, pc, p;
3095
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003096 a = *lp++;
3097 b = *pp++;
3098 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003099
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003100 p = b - c;
3101 pc = a - c;
3102
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003103#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003104 pa = abs(p);
3105 pb = abs(pc);
3106 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003107#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003108 pa = p < 0 ? -p : p;
3109 pb = pc < 0 ? -pc : pc;
3110 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003111#endif
3112
3113 /*
3114 if (pa <= pb && pa <= pc)
3115 p = a;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003116
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003117 else if (pb <= pc)
3118 p = b;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003119
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003120 else
3121 p = c;
3122 */
3123
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003124 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003125
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003126 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3127 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003128 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003129 break;
3130 }
3131 default:
Glenn Randers-Pehrsona272d8f2010-06-25 21:45:31 -05003132 png_error(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05003133 /*NOT REACHED */
3134 break;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003135 }
3136}
Guy Schalnat0d580581995-07-20 02:43:20 -05003137
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003138#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003139void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003140png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003141{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003142#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003143 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003144
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003145 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003146 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003147
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003148 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003149 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003150
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003151 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003152 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003153
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003154 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003155 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3156#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003157
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003158 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003159 png_ptr->row_number++;
3160 if (png_ptr->row_number < png_ptr->num_rows)
3161 return;
3162
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003163#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003164 if (png_ptr->interlaced)
3165 {
3166 png_ptr->row_number = 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003167
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003168 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003169
Guy Schalnat0d580581995-07-20 02:43:20 -05003170 do
3171 {
3172 png_ptr->pass++;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003173
Guy Schalnat0d580581995-07-20 02:43:20 -05003174 if (png_ptr->pass >= 7)
3175 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003176
Guy Schalnat0d580581995-07-20 02:43:20 -05003177 png_ptr->iwidth = (png_ptr->width +
3178 png_pass_inc[png_ptr->pass] - 1 -
3179 png_pass_start[png_ptr->pass]) /
3180 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003181
Guy Schalnat0d580581995-07-20 02:43:20 -05003182 if (!(png_ptr->transformations & PNG_INTERLACE))
3183 {
3184 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003185 png_pass_yinc[png_ptr->pass] - 1 -
3186 png_pass_ystart[png_ptr->pass]) /
3187 png_pass_yinc[png_ptr->pass];
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003188
Guy Schalnat0d580581995-07-20 02:43:20 -05003189 if (!(png_ptr->num_rows))
3190 continue;
3191 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003192
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003193 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003194 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003195 } while (png_ptr->iwidth == 0);
3196
3197 if (png_ptr->pass < 7)
3198 return;
3199 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003200#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003201
Guy Schalnate5a37791996-06-05 15:50:50 -05003202 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003203 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003204 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003205 char extra;
3206 int ret;
3207
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003208 png_ptr->zstream.next_out = (Byte *)&extra;
3209 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003210
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003211 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003212 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003213 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003214 {
3215 while (!png_ptr->idat_size)
3216 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003217 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003218
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003219 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003220
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003221 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003222 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003223 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003224 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003225
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003226 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003227 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003228
3229 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003230
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003231 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3232 png_ptr->zstream.next_in = png_ptr->zbuf;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003233
Guy Schalnat0d580581995-07-20 02:43:20 -05003234 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003235 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003236
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003237 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3238 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003239 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003240 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003241
Guy Schalnat0d580581995-07-20 02:43:20 -05003242 if (ret == Z_STREAM_END)
3243 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003244 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003245 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003246 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003247
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003248 png_ptr->mode |= PNG_AFTER_IDAT;
3249 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003250 break;
3251 }
3252 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003253 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003254 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003255
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003256 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003257 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003258 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003259 png_ptr->mode |= PNG_AFTER_IDAT;
3260 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3261 break;
3262 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003263
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003264 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003265 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003266 }
3267
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003268 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003269 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003270
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003271 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003272
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003273 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003274}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003275#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003276
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003277void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003278png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003279{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003280#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003281 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003282
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003283 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003284 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003285
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003286 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003287 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003288
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003289 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003290 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003291
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003292 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003293 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3294#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003295
Guy Schalnat0d580581995-07-20 02:43:20 -05003296 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003297 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003298
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003299 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003300 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003301 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003302#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003303 if (png_ptr->interlaced)
3304 {
3305 if (!(png_ptr->transformations & PNG_INTERLACE))
3306 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003307 png_pass_ystart[0]) / png_pass_yinc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05003308 else
3309 png_ptr->num_rows = png_ptr->height;
3310
3311 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003312 png_pass_inc[png_ptr->pass] - 1 -
3313 png_pass_start[png_ptr->pass]) /
3314 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003315 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003316
Guy Schalnat0d580581995-07-20 02:43:20 -05003317 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003318#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003319 {
3320 png_ptr->num_rows = png_ptr->height;
3321 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003322 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003323
Guy Schalnat0d580581995-07-20 02:43:20 -05003324 max_pixel_depth = png_ptr->pixel_depth;
3325
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003326#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003327 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003328 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003329#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003330
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003331#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003332 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003333 {
3334 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3335 {
3336 if (png_ptr->num_trans)
3337 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003338
Guy Schalnat0d580581995-07-20 02:43:20 -05003339 else
3340 max_pixel_depth = 24;
3341 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003342
Guy Schalnat0d580581995-07-20 02:43:20 -05003343 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3344 {
3345 if (max_pixel_depth < 8)
3346 max_pixel_depth = 8;
3347 if (png_ptr->num_trans)
3348 max_pixel_depth *= 2;
3349 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003350
Guy Schalnat0d580581995-07-20 02:43:20 -05003351 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3352 {
3353 if (png_ptr->num_trans)
3354 {
3355 max_pixel_depth *= 4;
3356 max_pixel_depth /= 3;
3357 }
3358 }
3359 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003360#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003361
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003362#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003363 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003364 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003365 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3366 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003367
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003368 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003369 {
3370 if (max_pixel_depth <= 8)
3371 max_pixel_depth = 16;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003372
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003373 else
3374 max_pixel_depth = 32;
3375 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003376
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003377 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3378 {
3379 if (max_pixel_depth <= 32)
3380 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003381
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003382 else
3383 max_pixel_depth = 64;
3384 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003385 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003386#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003387
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003388#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003389 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3390 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003391 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003392#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003393 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003394#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003395#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003396 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003397#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003398 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003399 {
3400 if (max_pixel_depth <= 16)
3401 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003402
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003403 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003404 max_pixel_depth = 64;
3405 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003406
Guy Schalnat0d580581995-07-20 02:43:20 -05003407 else
3408 {
3409 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003410 {
3411 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003412 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003413
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003414 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003415 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003416 }
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003417 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3418 max_pixel_depth = 64;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003419
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003420 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003421 max_pixel_depth = 48;
3422 }
3423 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003424#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003425
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003426#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3427defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003428 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003429 {
3430 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003431 png_ptr->user_transform_channels;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003432 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003433 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003434 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003435#endif
3436
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003437 /* Align the width on the next larger 8 pixels. Mainly used
3438 * for interlacing
3439 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003440 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003441 /* Calculate the maximum bytes needed, adding a byte and a pixel
3442 * for safety's sake
3443 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003444 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003445 1 + ((max_pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003446
Guy Schalnat0d580581995-07-20 02:43:20 -05003447#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003448 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003449 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003450#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003451
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003452 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003453 {
3454 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003455
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003456 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003457 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3458 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003459
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003460 else
3461 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3462 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003463
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003464 png_ptr->old_big_row_buf_size = row_bytes + 48;
3465
3466#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3467 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3468 * of padding before and after row_buf.
3469 */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003470 png_ptr->row_buf = png_ptr->big_row_buf + 32 -
3471 (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F);
3472
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003473 png_ptr->old_big_row_buf_size = row_bytes + 48;
3474#else
3475 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003476 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003477#endif
3478 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003479 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003480
3481#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003482 if (png_ptr->rowbytes > 65535)
Guy Schalnate5a37791996-06-05 15:50:50 -05003483 png_error(png_ptr, "This image requires a row greater than 64KB");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003484
Guy Schalnat0d580581995-07-20 02:43:20 -05003485#endif
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003486 if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003487 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003488
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003489 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003490 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003491 png_free(png_ptr, png_ptr->prev_row);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003492
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003493 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003494
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003495 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003496 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003497
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003498 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003499
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003500 png_debug1(3, "width = %u,", png_ptr->width);
3501 png_debug1(3, "height = %u,", png_ptr->height);
3502 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3503 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3504 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3505 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003506 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003507
Guy Schalnate5a37791996-06-05 15:50:50 -05003508 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003509}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003510
3511#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
3512int PNGAPI
3513png_get_num_passes(png_structp png_ptr)
3514{
3515 if (png_ptr != NULL)
3516 {
3517 if (png_ptr->interlaced)
3518 return 7;
3519 else
3520 return 1;
3521 }
3522
3523 /* Here on error */
3524 return 0;
3525}
3526
3527png_uint_32 PNGAPI
3528png_get_num_rows(png_structp png_ptr)
3529{
3530 if (png_ptr != NULL)
3531 {
3532 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003533 return png_ptr->num_rows;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003534 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003535 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3536 "before png_get_num_rows");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003537 }
3538
3539 /* Here on error */
3540 return 0;
3541}
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003542
3543png_uint_32 PNGAPI
3544png_get_num_cols(png_structp png_ptr)
3545{
3546 if (png_ptr != NULL)
3547 {
3548 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003549 return png_ptr->iwidth;
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003550 else
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003551 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3552 "before png_get_num_cols");
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003553 }
3554
3555 /* Here on error */
3556 return 0;
3557}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003558#endif /* SEQUENTIAL READ */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003559#endif /* PNG_READ_SUPPORTED */