blob: 18c230362237d82321fe3f0c816461d0429160c1 [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-Pehrson33893092010-10-23 13:20:18 -050021#define png_strtod(p,a,b) strtod(a,b)
22
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060023png_uint_32 PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050024png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050025{
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060026 png_uint_32 uval = png_get_uint_32(buf);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -050027
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060028 if (uval > PNG_UINT_31_MAX)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060029 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -050030
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060031 return (uval);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050032}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050033
34#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
35/* The following is a variation on the above for use with the fixed
36 * point values used for gAMA and cHRM. Instead of png_error it
37 * issues a warning and returns (-1) - an invalid value because both
38 * gAMA and cHRM use *unsigned* integers for fixed point values.
39 */
40#define PNG_FIXED_ERROR (-1)
41
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050042static png_fixed_point /* PRIVATE */
43png_get_fixed_point(png_structp png_ptr, png_const_bytep buf)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050044{
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060045 png_uint_32 uval = png_get_uint_32(buf);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -050046
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060047 if (uval <= PNG_UINT_31_MAX)
48 return (png_fixed_point)uval; /* known to be in range */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050049
50 /* The caller can turn off the warning by passing NULL. */
51 if (png_ptr != NULL)
52 png_warning(png_ptr, "PNG fixed point integer out of range");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -050053
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050054 return PNG_FIXED_ERROR;
55}
56#endif
57
Glenn Randers-Pehrson34713ce2010-04-28 07:49:28 -050058#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
59/* NOTE: the read macros will obscure these definitions, so that if
60 * PNG_USE_READ_MACROS is set the library will not use them internally,
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060061 * but the APIs will still be available externally. The parentheses
62 * around "PNGAPI function_name" are necessary because ...
Glenn Randers-Pehrson34713ce2010-04-28 07:49:28 -050063 */
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060064
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050065/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050066png_uint_32 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050067png_get_uint_32)(png_const_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050068{
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060069 png_uint_32 uval =
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060070 ((png_uint_32)(*(buf )) << 24) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060071 ((png_uint_32)(*(buf + 1)) << 16) +
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060072 ((png_uint_32)(*(buf + 2)) << 8) +
73 ((png_uint_32)(*(buf + 3)) ) ;
Guy Schalnat0d580581995-07-20 02:43:20 -050074
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060075 return uval;
Guy Schalnat0d580581995-07-20 02:43:20 -050076}
77
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050078/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -050079 * data is stored in the PNG file in two's complement format and there
80 * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -050081 * the following code does a two's complement to native conversion.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050082 */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050083png_int_32 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050084png_get_int_32)(png_const_bytep buf)
Andreas Dilger47a0c421997-05-16 02:46:07 -050085{
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060086 png_uint_32 uval = png_get_uint_32(buf);
87 if ((uval & 0x80000000L) == 0) /* non-negative */
88 return uval;
Andreas Dilger47a0c421997-05-16 02:46:07 -050089
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060090 uval = (uval ^ 0xffffffffL) + 1; /* 2's complement: -x = ~x+1 */
91 return -(png_int_32)uval;
Andreas Dilger47a0c421997-05-16 02:46:07 -050092}
Andreas Dilger47a0c421997-05-16 02:46:07 -050093
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050094/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050095png_uint_16 (PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050096png_get_uint_16)(png_const_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050097{
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -060098 unsigned int val =
99 ((unsigned int)(*buf) << 8) +
100 ((unsigned int)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500101
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600102 return (png_uint_16)val;
Guy Schalnat0d580581995-07-20 02:43:20 -0500103}
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600104
Glenn Randers-Pehrson34713ce2010-04-28 07:49:28 -0500105#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -0500106
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600107/* Read and check the PNG file signature */
108void /* PRIVATE */
109png_read_sig(png_structp png_ptr, png_infop info_ptr)
110{
111 png_size_t num_checked, num_to_check;
112
113 /* Exit if the user application does not expect a signature. */
114 if (png_ptr->sig_bytes >= 8)
115 return;
116
117 num_checked = png_ptr->sig_bytes;
118 num_to_check = 8 - num_checked;
119
120#ifdef PNG_IO_STATE_SUPPORTED
121 png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;
122#endif
123
124 /* The signature must be serialized in a single I/O call. */
125 png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
126 png_ptr->sig_bytes = 8;
127
128 if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
129 {
130 if (num_checked < 4 &&
131 png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
132 png_error(png_ptr, "Not a PNG file");
133 else
134 png_error(png_ptr, "PNG file corrupted by ASCII conversion");
135 }
136 if (num_checked < 3)
137 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
138}
139
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500140/* Read the chunk header (length + type name).
141 * Put the type name into png_ptr->chunk_name, and return the length.
142 */
143png_uint_32 /* PRIVATE */
144png_read_chunk_header(png_structp png_ptr)
145{
146 png_byte buf[8];
147 png_uint_32 length;
148
149#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500150 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
151#endif
152
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600153 /* Read the length and the chunk name.
154 * This must be performed in a single I/O call.
155 */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500156 png_read_data(png_ptr, buf, 8);
157 length = png_get_uint_31(png_ptr, buf);
158
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600159 /* Put the chunk name into png_ptr->chunk_name. */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500160 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
161
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -0600162 png_debug2(0, "Reading %s chunk, length = %u",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600163 png_ptr->chunk_name, length);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500164
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600165 /* Reset the crc and run it over the chunk name. */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500166 png_reset_crc(png_ptr);
167 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
168
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600169 /* Check to see if chunk name is valid. */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500170 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
171
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500172#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500173 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
174#endif
175
176 return length;
177}
178
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500179/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500180void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500181png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500182{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500183 if (png_ptr == NULL)
184 return;
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500185
Guy Schalnat6d764711995-12-19 03:22:19 -0600186 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500187 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500188}
189
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600190/* Optionally skip data and then check the CRC. Depending on whether we
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500191 * are reading a ancillary or critical chunk, and how the program has set
192 * things up, we may calculate the CRC on the data and print a message.
193 * Returns '1' if there was a CRC error, '0' otherwise.
194 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500195int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600196png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500197{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500198 png_size_t i;
199 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500200
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500201 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600202 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500203 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500204 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500205
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500206 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500207 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500208 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500209 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600210
Andreas Dilger47a0c421997-05-16 02:46:07 -0500211 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600212 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500213 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500214 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500215 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600216 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600217 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600218 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600219 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500220
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600221 else
222 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500223 png_chunk_benign_error(png_ptr, "CRC error");
224 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600225 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500226
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600227 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600228 }
229
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600230 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500231}
232
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600233/* 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 -0500234 * the data it has read thus far.
235 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500236int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600237png_crc_error(png_structp png_ptr)
238{
239 png_byte crc_bytes[4];
240 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500241 int need_crc = 1;
242
243 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
244 {
245 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
246 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
247 need_crc = 0;
248 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500249
Andreas Dilger47a0c421997-05-16 02:46:07 -0500250 else /* critical */
251 {
252 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
253 need_crc = 0;
254 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600255
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500256#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500257 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
258#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500259
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600260 /* The chunk CRC must be serialized in a single I/O call. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600261 png_read_data(png_ptr, crc_bytes, 4);
262
Andreas Dilger47a0c421997-05-16 02:46:07 -0500263 if (need_crc)
264 {
265 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600266 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500267 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500268
Andreas Dilger47a0c421997-05-16 02:46:07 -0500269 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600270 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600271}
272
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600273#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500274 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600275static png_size_t
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500276png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600277 png_bytep output, png_size_t output_size)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600278{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600279 png_size_t count = 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600280
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500281 /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
282 * even necessarily handle 65536 bytes) because the type uInt is "16 bits or
283 * more". Consequently it is necessary to chunk the input to zlib. This
284 * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value
285 * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a
286 * lower value in pngpriv.h and this may sometimes have a performance
287 * advantage, because it forces access of the input data to be separated from
288 * at least some of the use by some period of time.
289 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500290 png_ptr->zstream.next_in = data;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500291 /* avail_in is set below from 'size' */
292 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600293
294 while (1)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600295 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600296 int ret, avail;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600297
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500298 /* The setting of 'avail_in' used to be outside the loop, by setting it
299 * inside it is possible to chunk the input to zlib and simply rely on
300 * zlib to advance the 'next_in' pointer. This allows arbitrary amounts o
301 * data to be passed through zlib at the unavoidable cost of requiring a
302 * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX
303 * input bytes.
304 */
305 if (png_ptr->zstream.avail_in == 0 && size > 0)
306 {
307 if (size <= ZLIB_IO_MAX)
308 {
309 /* The value is less than ZLIB_IO_MAX so the cast is safe: */
310 png_ptr->zstream.avail_in = (uInt)size;
311 size = 0;
312 }
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600313
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -0500314 else
315 {
316 png_ptr->zstream.avail_in = ZLIB_IO_MAX;
317 size -= ZLIB_IO_MAX;
318 }
319 }
320
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600321 /* Reset the output buffer each time round - we empty it
322 * after every inflate call.
323 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600324 png_ptr->zstream.next_out = png_ptr->zbuf;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600325 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600326
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600327 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
328 avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600329
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600330 /* First copy/count any new output - but only if we didn't
331 * get an error code.
332 */
333 if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600334 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500335 png_size_t space = avail; /* > 0, see above */
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500336
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600337 if (output != 0 && output_size > count)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600338 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500339 png_size_t copy = output_size - count;
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500340
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500341 if (space < copy)
342 copy = space;
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500343
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600344 png_memcpy(output + count, png_ptr->zbuf, copy);
345 }
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500346 count += space;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600347 }
348
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600349 if (ret == Z_OK)
350 continue;
351
352 /* Termination conditions - always reset the zstream, it
353 * must be left in inflateInit state.
354 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600355 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600356 inflateReset(&png_ptr->zstream);
357
358 if (ret == Z_STREAM_END)
359 return count; /* NOTE: may be zero. */
360
361 /* Now handle the error codes - the API always returns 0
362 * and the error message is dumped into the uncompressed
363 * buffer if available.
364 */
365 {
Glenn Randers-Pehrson6cac43c2010-06-26 12:33:17 -0500366 PNG_CONST char *msg;
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600367#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrsond9d4cec2010-07-12 07:12:09 -0500368 char umsg[52];
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600369#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600370 if (png_ptr->zstream.msg != 0)
371 msg = png_ptr->zstream.msg;
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500372
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600373 else
374 {
Glenn Randers-Pehrson6a9e4802010-02-19 09:47:43 -0600375#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600376 switch (ret)
377 {
378 case Z_BUF_ERROR:
379 msg = "Buffer error in compressed datastream in %s chunk";
380 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500381
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600382 case Z_DATA_ERROR:
383 msg = "Data error in compressed datastream in %s chunk";
384 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500385
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600386 default:
387 msg = "Incomplete compressed datastream in %s chunk";
388 break;
389 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600390
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600391 png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
392 msg = umsg;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600393#else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600394 msg = "Damaged compressed datastream in chunk other than IDAT";
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600395#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600396 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600397
398 png_warning(png_ptr, msg);
399 }
400
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600401 /* 0 means an error - notice that this code simply ignores
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600402 * zero length compressed chunks as a result.
403 */
404 return 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600405 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600406}
407
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600408/*
409 * Decompress trailing data in a chunk. The assumption is that chunkdata
410 * points at an allocated area holding the contents of a chunk with a
411 * trailing compressed part. What we get back is an allocated area
412 * holding the original prefix part and an uncompressed version of the
413 * trailing part (the malloc area passed in is freed).
414 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500415void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500416png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600417 png_size_t chunklength,
418 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600419{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600420 /* The caller should guarantee this */
421 if (prefix_size > chunklength)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600422 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600423 /* The recovery is to delete the chunk. */
424 png_warning(png_ptr, "invalid chunklength");
425 prefix_size = 0; /* To delete everything */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600426 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600427
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600428 else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600429 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600430 png_size_t expanded_size = png_inflate(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600431 (png_bytep)(png_ptr->chunkdata + prefix_size),
432 chunklength - prefix_size,
433 0, /*output*/
434 0); /*output size*/
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600435
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600436 /* Now check the limits on this chunk - if the limit fails the
437 * compressed data will be removed, the prefix will remain.
438 */
439#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
440 if (png_ptr->user_chunk_malloc_max &&
441 (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600442#else
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600443# ifdef PNG_USER_CHUNK_MALLOC_MAX
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600444 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
445 prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600446# endif
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600447#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600448 png_warning(png_ptr, "Exceeded size limit while expanding chunk");
449
450 /* If the size is zero either there was an error and a message
451 * has already been output (warning) or the size really is zero
452 * and we have nothing to do - the code will exit through the
453 * error case below.
454 */
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600455#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
456 defined(PNG_USER_CHUNK_MALLOC_MAX)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600457 else if (expanded_size > 0)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600458#else
459 if (expanded_size > 0)
460#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600461 {
462 /* Success (maybe) - really uncompress the chunk. */
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600463 png_size_t new_size = 0;
464 png_charp text = png_malloc_warn(png_ptr,
465 prefix_size + expanded_size + 1);
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600466
467 if (text != NULL)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600468 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600469 png_memcpy(text, png_ptr->chunkdata, prefix_size);
470 new_size = png_inflate(png_ptr,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600471 (png_bytep)(png_ptr->chunkdata + prefix_size),
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600472 chunklength - prefix_size,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600473 (png_bytep)(text + prefix_size), expanded_size);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600474 text[prefix_size + expanded_size] = 0; /* just in case */
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600475
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600476 if (new_size == expanded_size)
477 {
478 png_free(png_ptr, png_ptr->chunkdata);
479 png_ptr->chunkdata = text;
480 *newlength = prefix_size + expanded_size;
481 return; /* The success return! */
482 }
Glenn Randers-Pehrson821b7102010-06-24 16:16:32 -0500483
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600484 png_warning(png_ptr, "png_inflate logic error");
485 png_free(png_ptr, text);
486 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500487
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600488 else
489 png_warning(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600490 }
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600491 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600492
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600493 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
494 {
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600495#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600496 char umsg[50];
497
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600498 png_snprintf(umsg, sizeof umsg,
499 "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600500 png_warning(png_ptr, umsg);
501#else
502 png_warning(png_ptr, "Unknown zTXt compression type");
503#endif
504
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600505 /* The recovery is to simply drop the data. */
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600506 }
507
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600508 /* Generic error return - leave the prefix, delete the compressed
509 * data, reallocate the chunkdata to remove the potentially large
510 * amount of compressed data.
511 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600512 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600513 png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500514
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600515 if (text != NULL)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600516 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600517 if (prefix_size > 0)
Glenn Randers-Pehrson7d1f5912010-02-11 23:03:26 -0600518 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500519
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600520 png_free(png_ptr, png_ptr->chunkdata);
521 png_ptr->chunkdata = text;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600522
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600523 /* This is an extra zero in the 'uncompressed' part. */
524 *(png_ptr->chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500525 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600526 /* Ignore a malloc error here - it is safe. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600527 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600528
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600529 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600530}
531#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600532
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500533/* Read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500534void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600535png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500536{
537 png_byte buf[13];
538 png_uint_32 width, height;
539 int bit_depth, color_type, compression_type, filter_type;
540 int interlace_type;
541
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500542 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500543
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600544 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500545 png_error(png_ptr, "Out of place IHDR");
546
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500547 /* Check the length */
Guy Schalnat0d580581995-07-20 02:43:20 -0500548 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600549 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500550
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600551 png_ptr->mode |= PNG_HAVE_IHDR;
552
Guy Schalnat0d580581995-07-20 02:43:20 -0500553 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600554 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500555
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500556 width = png_get_uint_31(png_ptr, buf);
557 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500558 bit_depth = buf[8];
559 color_type = buf[9];
560 compression_type = buf[10];
561 filter_type = buf[11];
562 interlace_type = buf[12];
563
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500564 /* Set internal variables */
Guy Schalnat0d580581995-07-20 02:43:20 -0500565 png_ptr->width = width;
566 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600567 png_ptr->bit_depth = (png_byte)bit_depth;
568 png_ptr->interlaced = (png_byte)interlace_type;
569 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500570#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600571 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500572#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500573 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500574
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500575 /* Find number of channels */
Guy Schalnat0d580581995-07-20 02:43:20 -0500576 switch (png_ptr->color_type)
577 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500578 default: /* invalid, png_set_IHDR calls png_error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500579 case PNG_COLOR_TYPE_GRAY:
580 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500581 png_ptr->channels = 1;
582 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500583
Andreas Dilger47a0c421997-05-16 02:46:07 -0500584 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500585 png_ptr->channels = 3;
586 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500587
Andreas Dilger47a0c421997-05-16 02:46:07 -0500588 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500589 png_ptr->channels = 2;
590 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500591
Andreas Dilger47a0c421997-05-16 02:46:07 -0500592 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500593 png_ptr->channels = 4;
594 break;
595 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600596
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500597 /* Set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600598 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600599 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500600 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500601 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
602 png_debug1(3, "channels = %d", png_ptr->channels);
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -0600603 png_debug1(3, "rowbytes = %u", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500604 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600605 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500606}
607
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500608/* Read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500609void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600610png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500611{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600612 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600613 int num, i;
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500614#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500615 png_colorp pal_ptr;
616#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500617
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500618 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500619
Guy Schalnate5a37791996-06-05 15:50:50 -0500620 if (!(png_ptr->mode & PNG_HAVE_IHDR))
621 png_error(png_ptr, "Missing IHDR before PLTE");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500622
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600623 else if (png_ptr->mode & PNG_HAVE_IDAT)
624 {
625 png_warning(png_ptr, "Invalid PLTE after IDAT");
626 png_crc_finish(png_ptr, length);
627 return;
628 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500629
Guy Schalnate5a37791996-06-05 15:50:50 -0500630 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600631 png_error(png_ptr, "Duplicate PLTE chunk");
632
633 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500634
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500635 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
636 {
637 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600638 "Ignoring PLTE chunk in grayscale PNG");
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500639 png_crc_finish(png_ptr, length);
640 return;
641 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500642
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500643#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500644 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
645 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600646 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500647 return;
648 }
649#endif
650
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600651 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500652 {
653 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
654 {
655 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600656 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500657 return;
658 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500659
Guy Schalnate5a37791996-06-05 15:50:50 -0500660 else
661 {
662 png_error(png_ptr, "Invalid palette chunk");
663 }
664 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500665
666 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500667
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500668#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500669 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
670 {
671 png_byte buf[3];
672
673 png_crc_read(png_ptr, buf, 3);
674 pal_ptr->red = buf[0];
675 pal_ptr->green = buf[1];
676 pal_ptr->blue = buf[2];
677 }
678#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600679 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500680 {
681 png_byte buf[3];
682
683 png_crc_read(png_ptr, buf, 3);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500684 /* Don't depend upon png_color being any order */
Guy Schalnat0d580581995-07-20 02:43:20 -0500685 palette[i].red = buf[0];
686 palette[i].green = buf[1];
687 palette[i].blue = buf[2];
688 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500689#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600690
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600691 /* 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 -0500692 * whatever the normal CRC configuration tells us. However, if we
693 * have an RGB image, the PLTE can be considered ancillary, so
694 * we will act as though it is.
695 */
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500696#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600697 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600698#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600699 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500700 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600701 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500702
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500703#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600704 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
705 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600706 /* If we don't want to use the data from an ancillary chunk,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600707 * we have two options: an error abort, or a warning and we
708 * ignore the data in this chunk (which should be OK, since
709 * it's considered ancillary for a RGB or RGBA image).
710 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600711 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
712 {
713 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
714 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500715 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600716 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500717
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600718 else
719 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600720 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600721 return;
722 }
723 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500724
Andreas Dilger47a0c421997-05-16 02:46:07 -0500725 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600726 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
727 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600728 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600729 }
730 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600731#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500732
Andreas Dilger47a0c421997-05-16 02:46:07 -0500733 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500734
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500735#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500736 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
737 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600738 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500739 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500740 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500741 {
742 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500743 png_ptr->num_trans = (png_uint_16)num;
744 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500745
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500746 if (info_ptr->num_trans > (png_uint_16)num)
747 {
748 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
749 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500750 }
751 }
752 }
753#endif
754
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600755}
Guy Schalnate5a37791996-06-05 15:50:50 -0500756
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500757void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600758png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
759{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500760 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500761
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600762 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
763 {
764 png_error(png_ptr, "No image in file");
765 }
766
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600767 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600768
769 if (length != 0)
770 {
771 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600772 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500773
Andreas Dilger47a0c421997-05-16 02:46:07 -0500774 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500775
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500776 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500777}
778
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500779#ifdef PNG_READ_gAMA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500780void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600781png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500782{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600783 png_fixed_point igamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500784 png_byte buf[4];
785
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500786 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500787
Guy Schalnate5a37791996-06-05 15:50:50 -0500788 if (!(png_ptr->mode & PNG_HAVE_IHDR))
789 png_error(png_ptr, "Missing IHDR before gAMA");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500790
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600791 else if (png_ptr->mode & PNG_HAVE_IDAT)
792 {
793 png_warning(png_ptr, "Invalid gAMA after IDAT");
794 png_crc_finish(png_ptr, length);
795 return;
796 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500797
Guy Schalnate5a37791996-06-05 15:50:50 -0500798 else if (png_ptr->mode & PNG_HAVE_PLTE)
799 /* Should be an error, but we can cope with it */
800 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600801
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500802 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500803#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600804 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600805#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600806 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600807 {
808 png_warning(png_ptr, "Duplicate gAMA chunk");
809 png_crc_finish(png_ptr, length);
810 return;
811 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500812
Guy Schalnat0d580581995-07-20 02:43:20 -0500813 if (length != 4)
814 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600815 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600816 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500817 return;
818 }
819
820 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500821
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600822 if (png_crc_finish(png_ptr, 0))
823 return;
824
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500825 igamma = png_get_fixed_point(NULL, buf);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500826
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500827 /* Check for zero gamma or an error. */
828 if (igamma <= 0)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500829 {
830 png_warning(png_ptr,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500831 "Ignoring gAMA chunk with out of range gamma");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500832
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500833 return;
834 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500835
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500836# ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600837 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500838 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500839 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600840 {
841 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600842 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500843
844# ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600845 fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500846# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600847 return;
848 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500849 }
850# endif /* PNG_READ_sRGB_SUPPORTED */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600851
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600852# ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500853 /* Gamma correction on read is supported. */
854 png_ptr->gamma = igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600855# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500856 /* And set the 'info' structure members. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600857 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500858}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500859#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500860
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500861#ifdef PNG_READ_sBIT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500862void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600863png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500864{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500865 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600866 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600867
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500868 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500869
Guy Schalnat69b14481996-01-10 02:56:49 -0600870 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500871
Guy Schalnate5a37791996-06-05 15:50:50 -0500872 if (!(png_ptr->mode & PNG_HAVE_IHDR))
873 png_error(png_ptr, "Missing IHDR before sBIT");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500874
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600875 else if (png_ptr->mode & PNG_HAVE_IDAT)
876 {
877 png_warning(png_ptr, "Invalid sBIT after IDAT");
878 png_crc_finish(png_ptr, length);
879 return;
880 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500881
Guy Schalnate5a37791996-06-05 15:50:50 -0500882 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600883 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500884 /* Should be an error, but we can cope with it */
885 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600886 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500887
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500888 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600889 {
890 png_warning(png_ptr, "Duplicate sBIT chunk");
891 png_crc_finish(png_ptr, length);
892 return;
893 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500894
Guy Schalnat0d580581995-07-20 02:43:20 -0500895 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600896 truelen = 3;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500897
Guy Schalnat0d580581995-07-20 02:43:20 -0500898 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500899 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500900
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500901 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500902 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600903 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600904 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600905 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500906 }
907
Andreas Dilger47a0c421997-05-16 02:46:07 -0500908 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500909
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600910 if (png_crc_finish(png_ptr, 0))
911 return;
912
Guy Schalnat0d580581995-07-20 02:43:20 -0500913 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
914 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600915 png_ptr->sig_bit.red = buf[0];
916 png_ptr->sig_bit.green = buf[1];
917 png_ptr->sig_bit.blue = buf[2];
918 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500919 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500920
Guy Schalnat0d580581995-07-20 02:43:20 -0500921 else
922 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600923 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600924 png_ptr->sig_bit.red = buf[0];
925 png_ptr->sig_bit.green = buf[0];
926 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600927 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500928 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500929
Andreas Dilger47a0c421997-05-16 02:46:07 -0500930 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500931}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500932#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500933
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500934#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500935void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600936png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500937{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500938 png_byte buf[32];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500939 png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue,
940 y_blue;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600941
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500942 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500943
Guy Schalnate5a37791996-06-05 15:50:50 -0500944 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600945 png_error(png_ptr, "Missing IHDR before cHRM");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500946
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600947 else if (png_ptr->mode & PNG_HAVE_IDAT)
948 {
949 png_warning(png_ptr, "Invalid cHRM after IDAT");
950 png_crc_finish(png_ptr, length);
951 return;
952 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500953
Guy Schalnate5a37791996-06-05 15:50:50 -0500954 else if (png_ptr->mode & PNG_HAVE_PLTE)
955 /* Should be an error, but we can cope with it */
956 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600957
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500958 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500959# ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600960 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500961# endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600962 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600963 {
964 png_warning(png_ptr, "Duplicate cHRM chunk");
965 png_crc_finish(png_ptr, length);
966 return;
967 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500968
Guy Schalnat0d580581995-07-20 02:43:20 -0500969 if (length != 32)
970 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600971 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600972 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600973 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500974 }
975
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500976 png_crc_read(png_ptr, buf, 32);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500977
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500978 if (png_crc_finish(png_ptr, 0))
979 return;
980
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500981 x_white = png_get_fixed_point(NULL, buf);
982 y_white = png_get_fixed_point(NULL, buf + 4);
983 x_red = png_get_fixed_point(NULL, buf + 8);
984 y_red = png_get_fixed_point(NULL, buf + 12);
985 x_green = png_get_fixed_point(NULL, buf + 16);
986 y_green = png_get_fixed_point(NULL, buf + 20);
987 x_blue = png_get_fixed_point(NULL, buf + 24);
988 y_blue = png_get_fixed_point(NULL, buf + 28);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500989
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500990 if (x_white == PNG_FIXED_ERROR ||
991 y_white == PNG_FIXED_ERROR ||
992 x_red == PNG_FIXED_ERROR ||
993 y_red == PNG_FIXED_ERROR ||
994 x_green == PNG_FIXED_ERROR ||
995 y_green == PNG_FIXED_ERROR ||
996 x_blue == PNG_FIXED_ERROR ||
997 y_blue == PNG_FIXED_ERROR)
998 {
999 png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities");
1000 return;
1001 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001002
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001003#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -05001004 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001005 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001006 if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) ||
1007 PNG_OUT_OF_RANGE(y_white, 32900, 1000) ||
1008 PNG_OUT_OF_RANGE(x_red, 64000L, 1000) ||
1009 PNG_OUT_OF_RANGE(y_red, 33000, 1000) ||
1010 PNG_OUT_OF_RANGE(x_green, 30000, 1000) ||
1011 PNG_OUT_OF_RANGE(y_green, 60000L, 1000) ||
1012 PNG_OUT_OF_RANGE(x_blue, 15000, 1000) ||
1013 PNG_OUT_OF_RANGE(y_blue, 6000, 1000))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001014 {
1015 png_warning(png_ptr,
1016 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -05001017
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001018#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001019 fprintf(stderr, "wx=%d, wy=%d, rx=%d, ry=%d\n",
1020 x_white, y_white, x_red, y_red);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -05001021
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001022 fprintf(stderr, "gx=%d, gy=%d, bx=%d, by=%d\n",
1023 x_green, y_green, x_blue, y_blue);
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001024#endif /* PNG_CONSOLE_IO_SUPPORTED */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001025 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001026 return;
1027 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001028#endif /* PNG_READ_sRGB_SUPPORTED */
1029
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001030 png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
1031 x_green, y_green, x_blue, y_blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05001032}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001033#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001034
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001035#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001036void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001037png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1038{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001039 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001040 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001041
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001042 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001043
1044 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1045 png_error(png_ptr, "Missing IHDR before sRGB");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001046
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001047 else if (png_ptr->mode & PNG_HAVE_IDAT)
1048 {
1049 png_warning(png_ptr, "Invalid sRGB after IDAT");
1050 png_crc_finish(png_ptr, length);
1051 return;
1052 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001053
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001054 else if (png_ptr->mode & PNG_HAVE_PLTE)
1055 /* Should be an error, but we can cope with it */
1056 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001057
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001058 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001059 {
1060 png_warning(png_ptr, "Duplicate sRGB chunk");
1061 png_crc_finish(png_ptr, length);
1062 return;
1063 }
1064
1065 if (length != 1)
1066 {
1067 png_warning(png_ptr, "Incorrect sRGB chunk length");
1068 png_crc_finish(png_ptr, length);
1069 return;
1070 }
1071
1072 png_crc_read(png_ptr, buf, 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001073
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001074 if (png_crc_finish(png_ptr, 0))
1075 return;
1076
1077 intent = buf[0];
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001078
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001079 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001080 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001081 {
1082 png_warning(png_ptr, "Unknown sRGB intent");
1083 return;
1084 }
1085
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001086#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001087 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001088 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001089 if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001090 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001091 png_warning(png_ptr,
1092 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001093#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001094 fprintf(stderr, "incorrect gamma=(%d/100000)\n", info_ptr->gamma);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001095#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001096 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001097 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001098#endif /* PNG_READ_gAMA_SUPPORTED */
1099
1100#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001101 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001102 if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) ||
1103 PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) ||
1104 PNG_OUT_OF_RANGE(info_ptr->x_red, 64000L, 1000) ||
1105 PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) ||
1106 PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) ||
1107 PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) ||
1108 PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) ||
1109 PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001110 {
1111 png_warning(png_ptr,
1112 "Ignoring incorrect cHRM value when sRGB is also present");
1113 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001114#endif /* PNG_READ_cHRM_SUPPORTED */
1115
1116 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1117}
1118#endif /* PNG_READ_sRGB_SUPPORTED */
1119
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001120#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001121void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001122png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1123/* Note: this does not properly handle chunks that are > 64K under DOS */
1124{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001125 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001126 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001127 png_charp profile;
1128 png_uint_32 skip = 0;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001129 png_uint_32 profile_size;
1130 png_alloc_size_t profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001131 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001132
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001133 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001134
1135 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1136 png_error(png_ptr, "Missing IHDR before iCCP");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001137
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001138 else if (png_ptr->mode & PNG_HAVE_IDAT)
1139 {
1140 png_warning(png_ptr, "Invalid iCCP after IDAT");
1141 png_crc_finish(png_ptr, length);
1142 return;
1143 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001144
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001145 else if (png_ptr->mode & PNG_HAVE_PLTE)
1146 /* Should be an error, but we can cope with it */
1147 png_warning(png_ptr, "Out of place iCCP chunk");
1148
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001149 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001150 {
1151 png_warning(png_ptr, "Duplicate iCCP chunk");
1152 png_crc_finish(png_ptr, length);
1153 return;
1154 }
1155
1156#ifdef PNG_MAX_MALLOC_64K
1157 if (length > (png_uint_32)65535L)
1158 {
1159 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1160 skip = length - (png_uint_32)65535L;
1161 length = (png_uint_32)65535L;
1162 }
1163#endif
1164
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001165 png_free(png_ptr, png_ptr->chunkdata);
1166 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001167 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001168 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001169
1170 if (png_crc_finish(png_ptr, skip))
1171 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001172 png_free(png_ptr, png_ptr->chunkdata);
1173 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001174 return;
1175 }
1176
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001177 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001178
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001179 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001180 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001181
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001182 ++profile;
1183
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001184 /* There should be at least one zero (the compression type byte)
1185 * following the separator, and we should be on it
1186 */
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -05001187 if (profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001188 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001189 png_free(png_ptr, png_ptr->chunkdata);
1190 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001191 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001192 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001193 }
1194
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001195 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001196 compression_type = *profile++;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001197
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001198 if (compression_type)
1199 {
1200 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001201 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001202 wrote nonzero) */
1203 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001204
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001205 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001206 png_decompress_chunk(png_ptr, compression_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001207 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001208
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001209 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001210
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001211 if (prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001212 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001213 png_free(png_ptr, png_ptr->chunkdata);
1214 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001215 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1216 return;
1217 }
1218
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001219 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001220 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001221 profile_size = ((*(pC )) << 24) |
1222 ((*(pC + 1)) << 16) |
1223 ((*(pC + 2)) << 8) |
1224 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001225
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001226 /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
1227 * because profile_size is a 32 bit value.
1228 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001229 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001230 profile_length = profile_size;
1231
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001232 /* And the following guarantees that profile_size == profile_length. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001233 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001234 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001235 png_free(png_ptr, png_ptr->chunkdata);
1236 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001237#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001238 {
1239 char umsg[80];
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001240
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001241 png_snprintf2(umsg, 80,
1242 "Ignoring iCCP chunk with declared size = %u "
1243 "and actual length = %u", profile_size, profile_length);
1244 png_warning(png_ptr, umsg);
1245 }
1246#else
1247 png_warning(png_ptr,
1248 "Ignoring iCCP chunk with uncompressed size mismatch");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001249#endif
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001250 return;
1251 }
1252
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001253 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001254 compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001255 profile_size);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001256 png_free(png_ptr, png_ptr->chunkdata);
1257 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001258}
1259#endif /* PNG_READ_iCCP_SUPPORTED */
1260
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001261#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001262void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001263png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1264/* Note: this does not properly handle chunks that are > 64K under DOS */
1265{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001266 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001267 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001268#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001269 png_sPLT_entryp pp;
1270#endif
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001271 png_uint_32 data_length;
1272 int entry_size, i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001273 png_uint_32 skip = 0;
1274 png_size_t slength;
Glenn Randers-Pehrsonc1270572010-10-12 12:13:19 -05001275 png_uint_32 dl;
1276 png_size_t max_dl;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001277
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001278 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001279
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001280#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001281
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001282 if (png_ptr->user_chunk_cache_max != 0)
1283 {
1284 if (png_ptr->user_chunk_cache_max == 1)
1285 {
1286 png_crc_finish(png_ptr, length);
1287 return;
1288 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001289
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001290 if (--png_ptr->user_chunk_cache_max == 1)
1291 {
1292 png_warning(png_ptr, "No space in chunk cache for sPLT");
1293 png_crc_finish(png_ptr, length);
1294 return;
1295 }
1296 }
1297#endif
1298
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001299 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1300 png_error(png_ptr, "Missing IHDR before sPLT");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001301
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001302 else if (png_ptr->mode & PNG_HAVE_IDAT)
1303 {
1304 png_warning(png_ptr, "Invalid sPLT after IDAT");
1305 png_crc_finish(png_ptr, length);
1306 return;
1307 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001308
1309#ifdef PNG_MAX_MALLOC_64K
1310 if (length > (png_uint_32)65535L)
1311 {
1312 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1313 skip = length - (png_uint_32)65535L;
1314 length = (png_uint_32)65535L;
1315 }
1316#endif
1317
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001318 png_free(png_ptr, png_ptr->chunkdata);
1319 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001320
1321 /* WARNING: this may break if size_t is less than 32 bits; it is assumed
1322 * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
1323 * potential breakage point if the types in pngconf.h aren't exactly right.
1324 */
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001325 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001326 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001327
1328 if (png_crc_finish(png_ptr, skip))
1329 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001330 png_free(png_ptr, png_ptr->chunkdata);
1331 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001332 return;
1333 }
1334
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001335 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001336
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001337 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1338 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001339 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001340
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001341 ++entry_start;
1342
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001343 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001344 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001345 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001346 png_free(png_ptr, png_ptr->chunkdata);
1347 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001348 png_warning(png_ptr, "malformed sPLT chunk");
1349 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001350 }
1351
1352 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001353 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05001354 /* This must fit in a png_uint_32 because it is derived from the original
1355 * chunk data length (and use 'length', not 'slength' here for clarity -
1356 * they are guaranteed to be the same, see the tests above.)
1357 */
1358 data_length = length - (png_uint_32)(entry_start -
1359 (png_bytep)png_ptr->chunkdata);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001360
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001361 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001362 if (data_length % entry_size)
1363 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001364 png_free(png_ptr, png_ptr->chunkdata);
1365 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001366 png_warning(png_ptr, "sPLT chunk has bad length");
1367 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001368 }
1369
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -05001370 dl = (png_int_32)(data_length / entry_size);
Glenn Randers-Pehrsonc1270572010-10-12 12:13:19 -05001371 max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry);
1372
1373 if (dl > max_dl)
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001374 {
1375 png_warning(png_ptr, "sPLT chunk too long");
1376 return;
1377 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001378
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -05001379 new_palette.nentries = (png_int_32)(data_length / entry_size);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001380
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001381 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001382 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001383
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001384 if (new_palette.entries == NULL)
1385 {
1386 png_warning(png_ptr, "sPLT chunk requires too much memory");
1387 return;
1388 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001389
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001390#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001391 for (i = 0; i < new_palette.nentries; i++)
1392 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001393 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001394
1395 if (new_palette.depth == 8)
1396 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001397 pp->red = *entry_start++;
1398 pp->green = *entry_start++;
1399 pp->blue = *entry_start++;
1400 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001401 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001402
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001403 else
1404 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001405 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1406 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1407 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1408 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001409 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001410
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001411 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1412 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001413#else
1414 pp = new_palette.entries;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001415
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001416 for (i = 0; i < new_palette.nentries; i++)
1417 {
1418
1419 if (new_palette.depth == 8)
1420 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001421 pp[i].red = *entry_start++;
1422 pp[i].green = *entry_start++;
1423 pp[i].blue = *entry_start++;
1424 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001425 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001426
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001427 else
1428 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001429 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1430 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1431 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1432 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001433 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001434
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001435 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1436 }
1437#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001438
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001439 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001440 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001441
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001442 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001443
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001444 png_free(png_ptr, png_ptr->chunkdata);
1445 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001446 png_free(png_ptr, new_palette.entries);
1447}
1448#endif /* PNG_READ_sPLT_SUPPORTED */
1449
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001450#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001451void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001452png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001453{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001454 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001455
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001456 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001457
Guy Schalnate5a37791996-06-05 15:50:50 -05001458 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1459 png_error(png_ptr, "Missing IHDR before tRNS");
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001460
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001461 else if (png_ptr->mode & PNG_HAVE_IDAT)
1462 {
1463 png_warning(png_ptr, "Invalid tRNS after IDAT");
1464 png_crc_finish(png_ptr, length);
1465 return;
1466 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001467
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001468 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001469 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001470 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001471 png_crc_finish(png_ptr, length);
1472 return;
1473 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001474
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001475 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001476 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001477 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001478
1479 if (length != 2)
1480 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001481 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001482 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001483 return;
1484 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001485
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001486 png_crc_read(png_ptr, buf, 2);
1487 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001488 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001489 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001490
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001491 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1492 {
1493 png_byte buf[6];
1494
1495 if (length != 6)
1496 {
1497 png_warning(png_ptr, "Incorrect tRNS chunk length");
1498 png_crc_finish(png_ptr, length);
1499 return;
1500 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001501
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001502 png_crc_read(png_ptr, buf, (png_size_t)length);
1503 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001504 png_ptr->trans_color.red = png_get_uint_16(buf);
1505 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1506 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001507 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001508
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001509 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1510 {
1511 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1512 {
1513 /* Should be an error, but we can cope with it. */
1514 png_warning(png_ptr, "Missing PLTE before tRNS");
1515 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001516
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001517 if (length > (png_uint_32)png_ptr->num_palette ||
1518 length > PNG_MAX_PALETTE_LENGTH)
1519 {
1520 png_warning(png_ptr, "Incorrect tRNS chunk length");
1521 png_crc_finish(png_ptr, length);
1522 return;
1523 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001524
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001525 if (length == 0)
1526 {
1527 png_warning(png_ptr, "Zero length tRNS chunk");
1528 png_crc_finish(png_ptr, length);
1529 return;
1530 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001531
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001532 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1533 png_ptr->num_trans = (png_uint_16)length;
1534 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001535
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001536 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001537 {
1538 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001539 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001540 return;
1541 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001542
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001543 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001544 {
1545 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001546 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001547 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001548
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001549 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001550 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001551}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001552#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001553
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001554#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001555void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001556png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001557{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001558 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001559 png_byte buf[6];
1560
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001561 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562
Guy Schalnate5a37791996-06-05 15:50:50 -05001563 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1564 png_error(png_ptr, "Missing IHDR before bKGD");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001565
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001566 else if (png_ptr->mode & PNG_HAVE_IDAT)
1567 {
1568 png_warning(png_ptr, "Invalid bKGD after IDAT");
1569 png_crc_finish(png_ptr, length);
1570 return;
1571 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001572
Guy Schalnate5a37791996-06-05 15:50:50 -05001573 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001574 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001575 {
1576 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001577 png_crc_finish(png_ptr, length);
1578 return;
1579 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001580
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001581 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001582 {
1583 png_warning(png_ptr, "Duplicate bKGD chunk");
1584 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001585 return;
1586 }
1587
Guy Schalnat0d580581995-07-20 02:43:20 -05001588 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1589 truelen = 1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001590
Guy Schalnat0d580581995-07-20 02:43:20 -05001591 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1592 truelen = 6;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001593
Guy Schalnat0d580581995-07-20 02:43:20 -05001594 else
1595 truelen = 2;
1596
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001597 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001598 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001599 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001600 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001601 return;
1602 }
1603
Andreas Dilger47a0c421997-05-16 02:46:07 -05001604 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001605
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001606 if (png_crc_finish(png_ptr, 0))
1607 return;
1608
Guy Schalnate5a37791996-06-05 15:50:50 -05001609 /* We convert the index value into RGB components so that we can allow
1610 * arbitrary RGB values for background when we have transparency, and
1611 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001612 * from the info_ptr struct.
1613 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001614 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001615 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001616 png_ptr->background.index = buf[0];
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001617
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001618 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001619 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001620 if (buf[0] >= info_ptr->num_palette)
1621 {
1622 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1623 return;
1624 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001625
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001626 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001627 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001628
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001629 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001630 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001631
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001632 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001633 (png_uint_16)png_ptr->palette[buf[0]].blue;
1634 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001635 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001636
Andreas Dilger47a0c421997-05-16 02:46:07 -05001637 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001638 {
1639 png_ptr->background.red =
1640 png_ptr->background.green =
1641 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001642 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001643 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001644
Guy Schalnat0d580581995-07-20 02:43:20 -05001645 else
1646 {
1647 png_ptr->background.red = png_get_uint_16(buf);
1648 png_ptr->background.green = png_get_uint_16(buf + 2);
1649 png_ptr->background.blue = png_get_uint_16(buf + 4);
1650 }
1651
Andreas Dilger47a0c421997-05-16 02:46:07 -05001652 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001653}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001654#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001655
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001656#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001657void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001658png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001659{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001660 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001661 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001662
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001663 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001664
Guy Schalnate5a37791996-06-05 15:50:50 -05001665 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1666 png_error(png_ptr, "Missing IHDR before hIST");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001667
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001668 else if (png_ptr->mode & PNG_HAVE_IDAT)
1669 {
1670 png_warning(png_ptr, "Invalid hIST after IDAT");
1671 png_crc_finish(png_ptr, length);
1672 return;
1673 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001674
Guy Schalnate5a37791996-06-05 15:50:50 -05001675 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1676 {
1677 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001678 png_crc_finish(png_ptr, length);
1679 return;
1680 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001681
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001682 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001683 {
1684 png_warning(png_ptr, "Duplicate hIST chunk");
1685 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001686 return;
1687 }
1688
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001689 num = length / 2 ;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001690
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -05001691 if (num != (unsigned int)png_ptr->num_palette || num >
1692 (unsigned int)PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001693 {
1694 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001695 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001696 return;
1697 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001698
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001699 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001700 {
1701 png_byte buf[2];
1702
1703 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001704 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001705 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001706
1707 if (png_crc_finish(png_ptr, 0))
1708 return;
1709
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001710 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001711}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001712#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001713
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001714#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001715void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001716png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001717{
1718 png_byte buf[9];
1719 png_uint_32 res_x, res_y;
1720 int unit_type;
1721
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001722 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001723
Guy Schalnate5a37791996-06-05 15:50:50 -05001724 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001725 png_error(png_ptr, "Missing IHDR before pHYs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001726
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001727 else if (png_ptr->mode & PNG_HAVE_IDAT)
1728 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001729 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001730 png_crc_finish(png_ptr, length);
1731 return;
1732 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001733
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001734 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001735 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001736 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001737 png_crc_finish(png_ptr, length);
1738 return;
1739 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001740
Guy Schalnat0d580581995-07-20 02:43:20 -05001741 if (length != 9)
1742 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001743 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001744 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001745 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001746 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001747
1748 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001749
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001750 if (png_crc_finish(png_ptr, 0))
1751 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001752
1753 res_x = png_get_uint_32(buf);
1754 res_y = png_get_uint_32(buf + 4);
1755 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001756 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001757}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001758#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001759
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001760#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001761void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001762png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001763{
1764 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001765 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001766 int unit_type;
1767
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001768 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001769
Guy Schalnate5a37791996-06-05 15:50:50 -05001770 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1771 png_error(png_ptr, "Missing IHDR before oFFs");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001772
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001773 else if (png_ptr->mode & PNG_HAVE_IDAT)
1774 {
1775 png_warning(png_ptr, "Invalid oFFs after IDAT");
1776 png_crc_finish(png_ptr, length);
1777 return;
1778 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001779
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001780 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001781 {
1782 png_warning(png_ptr, "Duplicate oFFs chunk");
1783 png_crc_finish(png_ptr, length);
1784 return;
1785 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001786
Guy Schalnat0d580581995-07-20 02:43:20 -05001787 if (length != 9)
1788 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001789 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001790 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001791 return;
1792 }
1793
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001794 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001795
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001796 if (png_crc_finish(png_ptr, 0))
1797 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001798
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001799 offset_x = png_get_int_32(buf);
1800 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001801 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001802 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1803}
1804#endif
1805
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001806#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001807/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001808void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001809png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1810{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001811 png_int_32 X0, X1;
1812 png_byte type, nparams;
1813 png_charp buf, units, endptr;
1814 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001815 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001816 int i;
1817
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001818 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001819
1820 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1821 png_error(png_ptr, "Missing IHDR before pCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001822
Andreas Dilger47a0c421997-05-16 02:46:07 -05001823 else if (png_ptr->mode & PNG_HAVE_IDAT)
1824 {
1825 png_warning(png_ptr, "Invalid pCAL after IDAT");
1826 png_crc_finish(png_ptr, length);
1827 return;
1828 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001829
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001830 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001831 {
1832 png_warning(png_ptr, "Duplicate pCAL chunk");
1833 png_crc_finish(png_ptr, length);
1834 return;
1835 }
1836
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001837 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001838 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001839 png_free(png_ptr, png_ptr->chunkdata);
1840 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001841
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001842 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001843 {
1844 png_warning(png_ptr, "No memory for pCAL purpose");
1845 return;
1846 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001847
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001848 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001849 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001850
1851 if (png_crc_finish(png_ptr, 0))
1852 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001853 png_free(png_ptr, png_ptr->chunkdata);
1854 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001855 return;
1856 }
1857
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001858 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001859
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001860 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001861 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001862 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001863
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001864 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001865
1866 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001867 * in order to get the parameter information.
1868 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001869 if (endptr <= buf + 12)
1870 {
1871 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001872 png_free(png_ptr, png_ptr->chunkdata);
1873 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001874 return;
1875 }
1876
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001877 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001878 X0 = png_get_int_32((png_bytep)buf+1);
1879 X1 = png_get_int_32((png_bytep)buf+5);
1880 type = buf[9];
1881 nparams = buf[10];
1882 units = buf + 11;
1883
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001884 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001885 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001886 * equation types.
1887 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001888 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1889 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1890 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1891 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1892 {
1893 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001894 png_free(png_ptr, png_ptr->chunkdata);
1895 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001896 return;
1897 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001898
Andreas Dilger47a0c421997-05-16 02:46:07 -05001899 else if (type >= PNG_EQUATION_LAST)
1900 {
1901 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1902 }
1903
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001904 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001905 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001906
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001907 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001908
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001909 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001910 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001911
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001912 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001913 {
1914 png_free(png_ptr, png_ptr->chunkdata);
1915 png_ptr->chunkdata = NULL;
1916 png_warning(png_ptr, "No memory for pCAL params");
1917 return;
1918 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001919
1920 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001921 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001922 {
1923 buf++; /* Skip the null string terminator from previous parameter. */
1924
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001925 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001926
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001927 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001928 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001929
1930 /* Make sure we haven't run out of data yet */
1931 if (buf > endptr)
1932 {
1933 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001934 png_free(png_ptr, png_ptr->chunkdata);
1935 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001936 png_free(png_ptr, params);
1937 return;
1938 }
1939 }
1940
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001941 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001942 units, params);
1943
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001944 png_free(png_ptr, png_ptr->chunkdata);
1945 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001946 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001947}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001948#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001949
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001950#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001951/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001952void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001953png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1954{
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001955 png_size_t slength, index;
1956 int state;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001957
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001958 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001959
1960 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1961 png_error(png_ptr, "Missing IHDR before sCAL");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001962
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001963 else if (png_ptr->mode & PNG_HAVE_IDAT)
1964 {
1965 png_warning(png_ptr, "Invalid sCAL after IDAT");
1966 png_crc_finish(png_ptr, length);
1967 return;
1968 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001969
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001970 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001971 {
1972 png_warning(png_ptr, "Duplicate sCAL chunk");
1973 png_crc_finish(png_ptr, length);
1974 return;
1975 }
1976
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001977 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001978 length + 1);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05001979
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001980 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001981
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001982 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001983 {
1984 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05001985 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001986 return;
1987 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001988
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001989 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001990 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001991 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001992
1993 if (png_crc_finish(png_ptr, 0))
1994 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001995 png_free(png_ptr, png_ptr->chunkdata);
1996 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001997 return;
1998 }
1999
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002000 /* Validate the unit. */
2001 if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05002002 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002003 png_warning(png_ptr, "Invalid sCAL ignored: invalid unit");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05002004 png_free(png_ptr, png_ptr->chunkdata);
2005 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002006 return;
2007 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002008
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002009 /* Validate the ASCII numbers, need two ASCII numbers separated by
2010 * a '\0' and they need to fit exactly in the chunk data.
2011 */
2012 index = 0;
2013 state = 0;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002014
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002015 if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
2016 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
2017 index >= slength || png_ptr->chunkdata[index++] != 0)
2018 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002019
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002020 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002021 {
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002022 png_size_t heighti = index;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002023
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002024 if (png_ptr->chunkdata[index] == 45 /* negative height */ ||
2025 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &index) ||
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002026 index != slength)
2027 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002028
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002029 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002030 /* This is the (only) success case. */
2031 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
2032 png_ptr->chunkdata+1, png_ptr->chunkdata+heighti);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002033 }
2034
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002035 /* Clean up - just free the temporarily allocated buffer. */
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05002036 png_free(png_ptr, png_ptr->chunkdata);
2037 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002038}
2039#endif
2040
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002041#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002042void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002043png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002044{
2045 png_byte buf[7];
2046 png_time mod_time;
2047
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002048 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002049
Guy Schalnate5a37791996-06-05 15:50:50 -05002050 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002051 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002052
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002053 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002054 {
2055 png_warning(png_ptr, "Duplicate tIME chunk");
2056 png_crc_finish(png_ptr, length);
2057 return;
2058 }
2059
2060 if (png_ptr->mode & PNG_HAVE_IDAT)
2061 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05002062
Guy Schalnat0d580581995-07-20 02:43:20 -05002063 if (length != 7)
2064 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002065 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002066 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05002067 return;
2068 }
2069
2070 png_crc_read(png_ptr, buf, 7);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002071
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002072 if (png_crc_finish(png_ptr, 0))
2073 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002074
2075 mod_time.second = buf[6];
2076 mod_time.minute = buf[5];
2077 mod_time.hour = buf[4];
2078 mod_time.day = buf[3];
2079 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002080 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05002081
Andreas Dilger47a0c421997-05-16 02:46:07 -05002082 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05002083}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002084#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002085
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002086#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002087/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002088void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002089png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002090{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002091 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002092 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06002093 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002094 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002095 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002096 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002097
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002098 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05002099
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002100#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002101 if (png_ptr->user_chunk_cache_max != 0)
2102 {
2103 if (png_ptr->user_chunk_cache_max == 1)
2104 {
2105 png_crc_finish(png_ptr, length);
2106 return;
2107 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002108
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002109 if (--png_ptr->user_chunk_cache_max == 1)
2110 {
2111 png_warning(png_ptr, "No space in chunk cache for tEXt");
2112 png_crc_finish(png_ptr, length);
2113 return;
2114 }
2115 }
2116#endif
2117
Guy Schalnate5a37791996-06-05 15:50:50 -05002118 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2119 png_error(png_ptr, "Missing IHDR before tEXt");
2120
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002121 if (png_ptr->mode & PNG_HAVE_IDAT)
2122 png_ptr->mode |= PNG_AFTER_IDAT;
2123
Andreas Dilger47a0c421997-05-16 02:46:07 -05002124#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002125 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002126 {
2127 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002128 skip = length - (png_uint_32)65535L;
2129 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002130 }
2131#endif
2132
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002133 png_free(png_ptr, png_ptr->chunkdata);
2134
2135 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002136
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002137 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002138 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002139 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002140 return;
2141 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002142
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002143 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002144 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002145
2146 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002147 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002148 png_free(png_ptr, png_ptr->chunkdata);
2149 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002150 return;
2151 }
2152
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002153 key = png_ptr->chunkdata;
2154
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002155 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002156
2157 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002158 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002159
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002160 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002161 text++;
2162
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002163 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002164 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002165
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002166 if (text_ptr == NULL)
2167 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002168 png_warning(png_ptr, "Not enough memory to process text chunk");
2169 png_free(png_ptr, png_ptr->chunkdata);
2170 png_ptr->chunkdata = NULL;
2171 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002172 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002173
Andreas Dilger47a0c421997-05-16 02:46:07 -05002174 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2175 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002176 text_ptr->lang = NULL;
2177 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002178 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002179 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002180 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002181
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002182 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002183
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002184 png_free(png_ptr, png_ptr->chunkdata);
2185 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002186 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002187
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002188 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002189 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002190}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002191#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002192
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002193#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002194/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002195void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002196png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002197{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002198 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002199 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002200 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002201 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002202 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002203
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002204 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002205
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002206#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002207 if (png_ptr->user_chunk_cache_max != 0)
2208 {
2209 if (png_ptr->user_chunk_cache_max == 1)
2210 {
2211 png_crc_finish(png_ptr, length);
2212 return;
2213 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002214
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002215 if (--png_ptr->user_chunk_cache_max == 1)
2216 {
2217 png_warning(png_ptr, "No space in chunk cache for zTXt");
2218 png_crc_finish(png_ptr, length);
2219 return;
2220 }
2221 }
2222#endif
2223
Guy Schalnate5a37791996-06-05 15:50:50 -05002224 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2225 png_error(png_ptr, "Missing IHDR before zTXt");
2226
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002227 if (png_ptr->mode & PNG_HAVE_IDAT)
2228 png_ptr->mode |= PNG_AFTER_IDAT;
2229
Andreas Dilger47a0c421997-05-16 02:46:07 -05002230#ifdef PNG_MAX_MALLOC_64K
2231 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002232 * there is no hard and fast rule to tell us where to stop.
2233 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002234 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002235 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002236 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2237 png_crc_finish(png_ptr, length);
2238 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002239 }
2240#endif
2241
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002242 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002243 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002244
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002245 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002246 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002247 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2248 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002249 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002250
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002251 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002252 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002253
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002254 if (png_crc_finish(png_ptr, 0))
2255 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002256 png_free(png_ptr, png_ptr->chunkdata);
2257 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002258 return;
2259 }
2260
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002261 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002262
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002263 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002264 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002265
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002266 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002267 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002268 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002269 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002270 png_free(png_ptr, png_ptr->chunkdata);
2271 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002272 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002273 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002274
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002275 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002276 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002277 comp_type = *(++text);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002278
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002279 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2280 {
2281 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2282 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2283 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002284
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002285 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002286 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002287
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002288 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002289
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002290 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002291 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002292
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002293 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002294 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002295
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002296 if (text_ptr == NULL)
2297 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002298 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2299 png_free(png_ptr, png_ptr->chunkdata);
2300 png_ptr->chunkdata = NULL;
2301 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002302 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002303
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002304 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002305 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002306 text_ptr->lang = NULL;
2307 text_ptr->lang_key = NULL;
2308 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002309 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002310 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002311
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002312 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002313
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002314 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002315 png_free(png_ptr, png_ptr->chunkdata);
2316 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002317
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002318 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002319 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002320}
2321#endif
2322
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002323#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002324/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002325void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002326png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2327{
2328 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002329 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002330 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002331 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002332 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002333 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002334
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002335 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002336
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002337#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002338 if (png_ptr->user_chunk_cache_max != 0)
2339 {
2340 if (png_ptr->user_chunk_cache_max == 1)
2341 {
2342 png_crc_finish(png_ptr, length);
2343 return;
2344 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002345
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002346 if (--png_ptr->user_chunk_cache_max == 1)
2347 {
2348 png_warning(png_ptr, "No space in chunk cache for iTXt");
2349 png_crc_finish(png_ptr, length);
2350 return;
2351 }
2352 }
2353#endif
2354
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002355 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2356 png_error(png_ptr, "Missing IHDR before iTXt");
2357
2358 if (png_ptr->mode & PNG_HAVE_IDAT)
2359 png_ptr->mode |= PNG_AFTER_IDAT;
2360
2361#ifdef PNG_MAX_MALLOC_64K
2362 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002363 * there is no hard and fast rule to tell us where to stop.
2364 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002365 if (length > (png_uint_32)65535L)
2366 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002367 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2368 png_crc_finish(png_ptr, length);
2369 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002370 }
2371#endif
2372
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002373 png_free(png_ptr, png_ptr->chunkdata);
2374 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002375
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002376 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002377 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002378 png_warning(png_ptr, "No memory to process iTXt chunk");
2379 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002380 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002381
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002382 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002383 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002384
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002385 if (png_crc_finish(png_ptr, 0))
2386 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002387 png_free(png_ptr, png_ptr->chunkdata);
2388 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002389 return;
2390 }
2391
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002392 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002393
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002394 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002395 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002396
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002397 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002398
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002399 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002400 * translated keyword (possibly empty), and possibly some text after the
2401 * keyword
2402 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002403
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002404 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002405 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002406 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002407 png_free(png_ptr, png_ptr->chunkdata);
2408 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002409 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002410 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002411
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002412 else
2413 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002414 comp_flag = *lang++;
2415 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002416 }
2417
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002418 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002419 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002420
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002421 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002422
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002423 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002424 {
2425 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002426 png_free(png_ptr, png_ptr->chunkdata);
2427 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002428 return;
2429 }
2430
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002431 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002432 /* Empty loop */ ;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002433
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002434 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002435
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002436 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002437 {
2438 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002439 png_free(png_ptr, png_ptr->chunkdata);
2440 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002441 return;
2442 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002443
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002444 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002445
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002446 key=png_ptr->chunkdata;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002447
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002448 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002449 png_decompress_chunk(png_ptr, comp_type,
2450 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002451
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002452 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002453 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002454
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002455 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002456 png_sizeof(png_text));
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002457
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002458 if (text_ptr == NULL)
2459 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002460 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2461 png_free(png_ptr, png_ptr->chunkdata);
2462 png_ptr->chunkdata = NULL;
2463 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002464 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002465
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002466 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002467 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2468 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002469 text_ptr->itxt_length = data_len;
2470 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002471 text_ptr->key = png_ptr->chunkdata;
2472 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002473
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002474 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002475
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002476 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002477 png_free(png_ptr, png_ptr->chunkdata);
2478 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002479
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002480 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002481 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002482}
2483#endif
2484
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002485/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002486 * chunk. If there isn't a problem with the chunk itself (ie bad
2487 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2488 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2489 * case it will be saved away to be written out later.
2490 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002491void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002492png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2493{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002494 png_uint_32 skip = 0;
2495
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002496 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002497
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002498#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002499 if (png_ptr->user_chunk_cache_max != 0)
2500 {
2501 if (png_ptr->user_chunk_cache_max == 1)
2502 {
2503 png_crc_finish(png_ptr, length);
2504 return;
2505 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002506
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002507 if (--png_ptr->user_chunk_cache_max == 1)
2508 {
2509 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2510 png_crc_finish(png_ptr, length);
2511 return;
2512 }
2513 }
2514#endif
2515
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002516 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002517 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002518 PNG_IDAT;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002519
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002520 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002521 png_ptr->mode |= PNG_AFTER_IDAT;
2522 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002523
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002524 if (!(png_ptr->chunk_name[0] & 0x20))
2525 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002526#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002527 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002528 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002529#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002530 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002531#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002532 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002533#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002534 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002535 }
2536
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002537#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002538 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002539#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002540 || (png_ptr->read_user_chunk_fn != NULL)
2541#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002542 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002543 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002544#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002545 if (length > (png_uint_32)65535L)
2546 {
2547 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2548 skip = length - (png_uint_32)65535L;
2549 length = (png_uint_32)65535L;
2550 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002551#endif
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002552
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002553 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2554 (png_charp)png_ptr->chunk_name,
2555 png_sizeof(png_ptr->unknown_chunk.name));
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002556
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002557 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2558 = '\0';
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002559
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002560 png_ptr->unknown_chunk.size = (png_size_t)length;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002561
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002562 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002563 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002564
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002565 else
2566 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002567 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2568 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002569 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002570
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002571#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002572 if (png_ptr->read_user_chunk_fn != NULL)
2573 {
2574 /* Callback to user unknown chunk handler */
2575 int ret;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002576
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002577 ret = (*(png_ptr->read_user_chunk_fn))
2578 (png_ptr, &png_ptr->unknown_chunk);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002579
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002580 if (ret < 0)
2581 png_chunk_error(png_ptr, "error in user chunk");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002582
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002583 if (ret == 0)
2584 {
2585 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002586 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002587#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002588 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2589 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002590#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002591 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002592 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002593
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002594 png_set_unknown_chunks(png_ptr, info_ptr,
2595 &png_ptr->unknown_chunk, 1);
2596 }
2597 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002598
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002599 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002600#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002601 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002602
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002603 png_free(png_ptr, png_ptr->unknown_chunk.data);
2604 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002605 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002606
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002607 else
2608#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002609 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002610
2611 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002612
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002613#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002614 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002615#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002616}
2617
2618/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002619 * This function can't have the "critical chunk check" incorporated
2620 * into it, since in the future we will need to be able to call user
2621 * functions to handle unknown critical chunks after we check that
2622 * the chunk name itself is valid.
2623 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002624
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002625#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002626
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002627void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002628png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002629{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002630 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002631 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002632 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002633 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002634 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002635 }
2636}
2637
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002638/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002639 * row. This routine takes care of alpha and transparency if requested.
2640 * This routine also handles the two methods of progressive display
2641 * of interlaced images, depending on the mask value.
2642 * The mask value describes which pixels are to be combined with
2643 * the row. The pattern always repeats every 8 pixels, so just 8
2644 * bits are needed. A one indicates the pixel is to be combined,
2645 * a zero indicates the pixel is to be skipped. This is in addition
2646 * to any alpha or transparency value associated with the pixel. If
2647 * you want all pixels to be combined, pass 0xff (255) in mask.
2648 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002649
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002650void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002651png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002652{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002653 png_debug(1, "in png_combine_row");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002654
Guy Schalnat0d580581995-07-20 02:43:20 -05002655 if (mask == 0xff)
2656 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002657 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002658 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002659 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002660
Guy Schalnat0d580581995-07-20 02:43:20 -05002661 else
2662 {
2663 switch (png_ptr->row_info.pixel_depth)
2664 {
2665 case 1:
2666 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002667 png_bytep sp = png_ptr->row_buf + 1;
2668 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002669 int s_inc, s_start, s_end;
2670 int m = 0x80;
2671 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002672 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002673 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002674
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002675#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002676 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002677 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002678 s_start = 0;
2679 s_end = 7;
2680 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002681 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002682
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002683 else
2684#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002685 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002686 s_start = 7;
2687 s_end = 0;
2688 s_inc = -1;
2689 }
2690
2691 shift = s_start;
2692
2693 for (i = 0; i < row_width; i++)
2694 {
2695 if (m & mask)
2696 {
2697 int value;
2698
2699 value = (*sp >> shift) & 0x01;
2700 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2701 *dp |= (png_byte)(value << shift);
2702 }
2703
2704 if (shift == s_end)
2705 {
2706 shift = s_start;
2707 sp++;
2708 dp++;
2709 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002710
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002711 else
2712 shift += s_inc;
2713
2714 if (m == 1)
2715 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002716
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002717 else
2718 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002719 }
2720 break;
2721 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002722
Guy Schalnat0d580581995-07-20 02:43:20 -05002723 case 2:
2724 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002725 png_bytep sp = png_ptr->row_buf + 1;
2726 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002727 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002728 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002729 int shift;
2730 png_uint_32 i;
2731 png_uint_32 row_width = png_ptr->width;
2732 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002733
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002734#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002735 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002736 {
2737 s_start = 0;
2738 s_end = 6;
2739 s_inc = 2;
2740 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002741
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002742 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002743#endif
2744 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002745 s_start = 6;
2746 s_end = 0;
2747 s_inc = -2;
2748 }
2749
2750 shift = s_start;
2751
2752 for (i = 0; i < row_width; i++)
2753 {
2754 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002755 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002756 value = (*sp >> shift) & 0x03;
2757 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2758 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002759 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002760
2761 if (shift == s_end)
2762 {
2763 shift = s_start;
2764 sp++;
2765 dp++;
2766 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002767
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002768 else
2769 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002770
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002771 if (m == 1)
2772 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002773
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002774 else
2775 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002776 }
2777 break;
2778 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002779
Guy Schalnat0d580581995-07-20 02:43:20 -05002780 case 4:
2781 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002782 png_bytep sp = png_ptr->row_buf + 1;
2783 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002784 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002785 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002786 int shift;
2787 png_uint_32 i;
2788 png_uint_32 row_width = png_ptr->width;
2789 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002790
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002791#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002792 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002793 {
2794 s_start = 0;
2795 s_end = 4;
2796 s_inc = 4;
2797 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002798
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002799 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002800#endif
2801 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002802 s_start = 4;
2803 s_end = 0;
2804 s_inc = -4;
2805 }
2806 shift = s_start;
2807
2808 for (i = 0; i < row_width; i++)
2809 {
2810 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002811 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002812 value = (*sp >> shift) & 0xf;
2813 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2814 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002815 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002816
2817 if (shift == s_end)
2818 {
2819 shift = s_start;
2820 sp++;
2821 dp++;
2822 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002823
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002824 else
2825 shift += s_inc;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002826
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002827 if (m == 1)
2828 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002829
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002830 else
2831 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002832 }
2833 break;
2834 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002835
Guy Schalnat0d580581995-07-20 02:43:20 -05002836 default:
2837 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002838 png_bytep sp = png_ptr->row_buf + 1;
2839 png_bytep dp = row;
2840 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2841 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002842 png_uint_32 row_width = png_ptr->width;
2843 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002844
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002845 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002846 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002847 if (m & mask)
2848 {
2849 png_memcpy(dp, sp, pixel_bytes);
2850 }
2851
2852 sp += pixel_bytes;
2853 dp += pixel_bytes;
2854
2855 if (m == 1)
2856 m = 0x80;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002857
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002858 else
2859 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002860 }
2861 break;
2862 }
2863 }
2864 }
2865}
2866
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002867#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002868void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002869png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002870{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002871 png_row_infop row_info = &(png_ptr->row_info);
2872 png_bytep row = png_ptr->row_buf + 1;
2873 int pass = png_ptr->pass;
2874 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002875 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2876 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002877 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002878
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002879 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002880 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002881 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002882 png_uint_32 final_width;
2883
2884 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002885
2886 switch (row_info->pixel_depth)
2887 {
2888 case 1:
2889 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002890 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2891 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002892 int sshift, dshift;
2893 int s_start, s_end, s_inc;
2894 int jstop = png_pass_inc[pass];
2895 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002896 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002897 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002898
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002899#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002900 if (transformations & PNG_PACKSWAP)
2901 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002902 sshift = (int)((row_info->width + 7) & 0x07);
2903 dshift = (int)((final_width + 7) & 0x07);
2904 s_start = 7;
2905 s_end = 0;
2906 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002907 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002908
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002909 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002910#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002911 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002912 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2913 dshift = 7 - (int)((final_width + 7) & 0x07);
2914 s_start = 0;
2915 s_end = 7;
2916 s_inc = 1;
2917 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002918
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002919 for (i = 0; i < row_info->width; i++)
2920 {
2921 v = (png_byte)((*sp >> sshift) & 0x01);
2922 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002923 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002924 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2925 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002926
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002927 if (dshift == s_end)
2928 {
2929 dshift = s_start;
2930 dp--;
2931 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002932
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002933 else
2934 dshift += s_inc;
2935 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002936
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002937 if (sshift == s_end)
2938 {
2939 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002940 sp--;
2941 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002942
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002943 else
2944 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002945 }
2946 break;
2947 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002948
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 case 2:
2950 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002951 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2952 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2953 int sshift, dshift;
2954 int s_start, s_end, s_inc;
2955 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002956 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002957
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002958#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002959 if (transformations & PNG_PACKSWAP)
2960 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002961 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2962 dshift = (int)(((final_width + 3) & 0x03) << 1);
2963 s_start = 6;
2964 s_end = 0;
2965 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002966 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002967
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002968 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002969#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002970 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002971 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2972 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2973 s_start = 0;
2974 s_end = 6;
2975 s_inc = 2;
2976 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002977
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002978 for (i = 0; i < row_info->width; i++)
2979 {
2980 png_byte v;
2981 int j;
2982
2983 v = (png_byte)((*sp >> sshift) & 0x03);
2984 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002985 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002986 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2987 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002988
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002989 if (dshift == s_end)
2990 {
2991 dshift = s_start;
2992 dp--;
2993 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002994
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002995 else
2996 dshift += s_inc;
2997 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002998
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002999 if (sshift == s_end)
3000 {
3001 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05003002 sp--;
3003 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003004
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003005 else
3006 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003007 }
3008 break;
3009 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003010
Guy Schalnat0d580581995-07-20 02:43:20 -05003011 case 4:
3012 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003013 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
3014 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003015 int sshift, dshift;
3016 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003017 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003018 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003019
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003020#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003021 if (transformations & PNG_PACKSWAP)
3022 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003023 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
3024 dshift = (int)(((final_width + 1) & 0x01) << 2);
3025 s_start = 4;
3026 s_end = 0;
3027 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003028 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003029
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003030 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05003031#endif
3032 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003033 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
3034 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
3035 s_start = 0;
3036 s_end = 4;
3037 s_inc = 4;
3038 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003039
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003040 for (i = 0; i < row_info->width; i++)
3041 {
3042 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
3043 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003044
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003045 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003046 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003047 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
3048 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003049
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003050 if (dshift == s_end)
3051 {
3052 dshift = s_start;
3053 dp--;
3054 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003055
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003056 else
3057 dshift += s_inc;
3058 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003059
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003060 if (sshift == s_end)
3061 {
3062 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05003063 sp--;
3064 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003065
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003066 else
3067 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003068 }
3069 break;
3070 }
3071 default:
3072 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003073 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003074
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003075 png_bytep sp = row + (png_size_t)(row_info->width - 1)
3076 * pixel_bytes;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003077
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003078 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003079
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003080 int jstop = png_pass_inc[pass];
3081 png_uint_32 i;
3082
3083 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003084 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003085 png_byte v[8];
3086 int j;
3087
3088 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003089
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003090 for (j = 0; j < jstop; j++)
3091 {
3092 png_memcpy(dp, v, pixel_bytes);
3093 dp -= pixel_bytes;
3094 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003095
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003096 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003097 }
3098 break;
3099 }
3100 }
3101 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003102 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003103 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05003104#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003105 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05003106#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003107}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003108#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003109
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003110void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003111png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003112 png_const_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003113{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003114 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003115 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003116 switch (filter)
3117 {
3118 case PNG_FILTER_VALUE_NONE:
3119 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003120
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003121 case PNG_FILTER_VALUE_SUB:
3122 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003123 png_size_t i;
3124 png_size_t istop = row_info->rowbytes;
3125 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003126 png_bytep rp = row + bpp;
3127 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003128
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003129 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003130 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003131 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
3132 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003133 }
3134 break;
3135 }
3136 case PNG_FILTER_VALUE_UP:
3137 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003138 png_size_t i;
3139 png_size_t istop = row_info->rowbytes;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003140 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003141 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003142
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003143 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003144 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003145 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3146 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003147 }
3148 break;
3149 }
3150 case PNG_FILTER_VALUE_AVG:
3151 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003152 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003153 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003154 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003155 png_bytep lp = row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003156 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3157 png_size_t istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003158
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003159 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003160 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003161 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003162 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003163
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003164 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003165 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003166
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003167 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003168 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003169 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003170 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003171
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003172 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003173 }
3174 break;
3175 }
3176 case PNG_FILTER_VALUE_PAETH:
3177 {
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003178 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003179 png_bytep rp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003180 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003181 png_bytep lp = row;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05003182 png_const_bytep cp = prev_row;
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003183 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3184 png_size_t istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003185
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003186 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003187 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003188 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3189 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003190 }
3191
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003192 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003193 {
3194 int a, b, c, pa, pb, pc, p;
3195
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003196 a = *lp++;
3197 b = *pp++;
3198 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003199
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003200 p = b - c;
3201 pc = a - c;
3202
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003203#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003204 pa = abs(p);
3205 pb = abs(pc);
3206 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003207#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003208 pa = p < 0 ? -p : p;
3209 pb = pc < 0 ? -pc : pc;
3210 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003211#endif
3212
3213 /*
3214 if (pa <= pb && pa <= pc)
3215 p = a;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003216
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003217 else if (pb <= pc)
3218 p = b;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003219
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003220 else
3221 p = c;
3222 */
3223
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003224 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003225
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003226 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3227 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003228 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003229 break;
3230 }
3231 default:
Glenn Randers-Pehrsona272d8f2010-06-25 21:45:31 -05003232 png_error(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05003233 /*NOT REACHED */
3234 break;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003235 }
3236}
Guy Schalnat0d580581995-07-20 02:43:20 -05003237
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003238#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003239void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003240png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003241{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003242#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003243 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003244
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003245 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003246 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003247
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003248 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003249 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003250
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003251 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003252 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003253
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003254 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003255 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3256#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003257
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003258 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003259 png_ptr->row_number++;
3260 if (png_ptr->row_number < png_ptr->num_rows)
3261 return;
3262
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003263#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003264 if (png_ptr->interlaced)
3265 {
3266 png_ptr->row_number = 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003267
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003268 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003269
Guy Schalnat0d580581995-07-20 02:43:20 -05003270 do
3271 {
3272 png_ptr->pass++;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003273
Guy Schalnat0d580581995-07-20 02:43:20 -05003274 if (png_ptr->pass >= 7)
3275 break;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003276
Guy Schalnat0d580581995-07-20 02:43:20 -05003277 png_ptr->iwidth = (png_ptr->width +
3278 png_pass_inc[png_ptr->pass] - 1 -
3279 png_pass_start[png_ptr->pass]) /
3280 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003281
Guy Schalnat0d580581995-07-20 02:43:20 -05003282 if (!(png_ptr->transformations & PNG_INTERLACE))
3283 {
3284 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003285 png_pass_yinc[png_ptr->pass] - 1 -
3286 png_pass_ystart[png_ptr->pass]) /
3287 png_pass_yinc[png_ptr->pass];
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003288
Guy Schalnat0d580581995-07-20 02:43:20 -05003289 if (!(png_ptr->num_rows))
3290 continue;
3291 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003292
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003293 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003294 break;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003295
Guy Schalnat0d580581995-07-20 02:43:20 -05003296 } while (png_ptr->iwidth == 0);
3297
3298 if (png_ptr->pass < 7)
3299 return;
3300 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003301#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003302
Guy Schalnate5a37791996-06-05 15:50:50 -05003303 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003304 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003305 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003306 char extra;
3307 int ret;
3308
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003309 png_ptr->zstream.next_out = (Byte *)&extra;
3310 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003311
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003312 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003313 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003314 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003315 {
3316 while (!png_ptr->idat_size)
3317 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003318 png_crc_finish(png_ptr, 0);
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06003319 png_ptr->idat_size = png_read_chunk_header(png_ptr);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003320 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003321 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003322 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003323
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003324 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3325 png_ptr->zstream.next_in = png_ptr->zbuf;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003326
Guy Schalnat0d580581995-07-20 02:43:20 -05003327 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003328 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003329
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003330 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3331 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003332 }
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06003333
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003334 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003335
Guy Schalnat0d580581995-07-20 02:43:20 -05003336 if (ret == Z_STREAM_END)
3337 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003338 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003339 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003340 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003341
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003342 png_ptr->mode |= PNG_AFTER_IDAT;
3343 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003344 break;
3345 }
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06003346
Guy Schalnat0d580581995-07-20 02:43:20 -05003347 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003348 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003349 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003350
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003351 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003352 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003353 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003354 png_ptr->mode |= PNG_AFTER_IDAT;
3355 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3356 break;
3357 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003358
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003359 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003360 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003361 }
3362
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003363 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003364 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003365
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003366 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003367
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003368 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003369}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003370#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003371
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003372void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003373png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003374{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003375#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003376 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003377
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003378 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003379 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003380
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003381 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003382 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003383
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003384 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003385 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003386
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003387 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003388 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3389#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003390
Guy Schalnat0d580581995-07-20 02:43:20 -05003391 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003392 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003393
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003394 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003395 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003396 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003397#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003398 if (png_ptr->interlaced)
3399 {
3400 if (!(png_ptr->transformations & PNG_INTERLACE))
3401 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003402 png_pass_ystart[0]) / png_pass_yinc[0];
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003403
Guy Schalnat0d580581995-07-20 02:43:20 -05003404 else
3405 png_ptr->num_rows = png_ptr->height;
3406
3407 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003408 png_pass_inc[png_ptr->pass] - 1 -
3409 png_pass_start[png_ptr->pass]) /
3410 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003411 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003412
Guy Schalnat0d580581995-07-20 02:43:20 -05003413 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003414#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003415 {
3416 png_ptr->num_rows = png_ptr->height;
3417 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003418 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003419
Guy Schalnat0d580581995-07-20 02:43:20 -05003420 max_pixel_depth = png_ptr->pixel_depth;
3421
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003422#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003423 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003424 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003425#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003426
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003427#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003428 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003429 {
3430 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3431 {
3432 if (png_ptr->num_trans)
3433 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003434
Guy Schalnat0d580581995-07-20 02:43:20 -05003435 else
3436 max_pixel_depth = 24;
3437 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003438
Guy Schalnat0d580581995-07-20 02:43:20 -05003439 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3440 {
3441 if (max_pixel_depth < 8)
3442 max_pixel_depth = 8;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003443
Guy Schalnat0d580581995-07-20 02:43:20 -05003444 if (png_ptr->num_trans)
3445 max_pixel_depth *= 2;
3446 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003447
Guy Schalnat0d580581995-07-20 02:43:20 -05003448 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3449 {
3450 if (png_ptr->num_trans)
3451 {
3452 max_pixel_depth *= 4;
3453 max_pixel_depth /= 3;
3454 }
3455 }
3456 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003457#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003458
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003459#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003460 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003461 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003462 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3463 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003464
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003465 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003466 {
3467 if (max_pixel_depth <= 8)
3468 max_pixel_depth = 16;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003469
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003470 else
3471 max_pixel_depth = 32;
3472 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003473
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003474 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3475 {
3476 if (max_pixel_depth <= 32)
3477 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003478
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003479 else
3480 max_pixel_depth = 64;
3481 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003482 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003483#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003484
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003485#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003486 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3487 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003488 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003489#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003490 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003491#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003492#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003493 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003494#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003495 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003496 {
3497 if (max_pixel_depth <= 16)
3498 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003499
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003500 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003501 max_pixel_depth = 64;
3502 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003503
Guy Schalnat0d580581995-07-20 02:43:20 -05003504 else
3505 {
3506 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003507 {
3508 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003509 max_pixel_depth = 32;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003510
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003511 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003512 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003513 }
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003514
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003515 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3516 max_pixel_depth = 64;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003517
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003518 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003519 max_pixel_depth = 48;
3520 }
3521 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003522#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003523
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003524#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3525defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003526 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003527 {
3528 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003529 png_ptr->user_transform_channels;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003530
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003531 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003532 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003533 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003534#endif
3535
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003536 /* Align the width on the next larger 8 pixels. Mainly used
3537 * for interlacing
3538 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003539 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003540 /* Calculate the maximum bytes needed, adding a byte and a pixel
3541 * for safety's sake
3542 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003543 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003544 1 + ((max_pixel_depth + 7) >> 3);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003545
Guy Schalnat0d580581995-07-20 02:43:20 -05003546#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003547 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003548 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003549#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003550
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003551 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003552 {
3553 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003554
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003555 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003556 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3557 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003558
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003559 else
3560 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3561 row_bytes + 48);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003562
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003563 png_ptr->old_big_row_buf_size = row_bytes + 48;
3564
3565#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3566 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3567 * of padding before and after row_buf.
3568 */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003569 png_ptr->row_buf = png_ptr->big_row_buf + 32 -
3570 (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F);
3571
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003572 png_ptr->old_big_row_buf_size = row_bytes + 48;
3573#else
3574 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003575 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003576#endif
3577 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003578 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003579
3580#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003581 if (png_ptr->rowbytes > 65535)
Guy Schalnate5a37791996-06-05 15:50:50 -05003582 png_error(png_ptr, "This image requires a row greater than 64KB");
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003583
Guy Schalnat0d580581995-07-20 02:43:20 -05003584#endif
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003585 if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003586 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003587
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003588 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003589 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003590 png_free(png_ptr, png_ptr->prev_row);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003591
Glenn Randers-Pehrsonbcb3aac2010-09-10 22:05:27 -05003592 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05003593
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003594 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003595 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003596
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003597 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003598
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003599 png_debug1(3, "width = %u,", png_ptr->width);
3600 png_debug1(3, "height = %u,", png_ptr->height);
3601 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3602 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3603 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3604 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003605 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003606
Guy Schalnate5a37791996-06-05 15:50:50 -05003607 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003608}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003609
3610#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
3611int PNGAPI
3612png_get_num_passes(png_structp png_ptr)
3613{
3614 if (png_ptr != NULL)
3615 {
3616 if (png_ptr->interlaced)
3617 return 7;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003618
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003619 else
3620 return 1;
3621 }
3622
3623 /* Here on error */
3624 return 0;
3625}
3626
3627png_uint_32 PNGAPI
3628png_get_num_rows(png_structp png_ptr)
3629{
3630 if (png_ptr != NULL)
3631 {
3632 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003633 return png_ptr->num_rows;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05003634
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003635 else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05003636 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3637 "before png_get_num_rows");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003638 }
3639
3640 /* Here on error */
3641 return 0;
3642}
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003643
3644png_uint_32 PNGAPI
3645png_get_num_cols(png_structp png_ptr)
3646{
3647 if (png_ptr != NULL)
3648 {
3649 if (png_ptr->flags & PNG_FLAG_ROW_INIT)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003650 return png_ptr->iwidth;
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003651 else
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05003652 png_error(png_ptr, "Call png_start_read_image or png_read_update_info "
3653 "before png_get_num_cols");
Glenn Randers-Pehrson2be8b642010-07-29 19:09:18 -05003654 }
3655
3656 /* Here on error */
3657 return 0;
3658}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05003659#endif /* SEQUENTIAL READ */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003660#endif /* PNG_READ_SUPPORTED */