blob: e0a812d47940239c2a9506fc320bb4f9f3bf6142 [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-Pehrson3cd7cff2010-04-16 19:27:08 -05004 * Last changed in libpng 1.4.1 [April 17, 2010]
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06005 * Copyright (c) 1998-2010 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrson3e61d792009-06-24 09:31:28 -050012 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050013 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060014 * libpng itself during the course of reading an image.
15 */
Guy Schalnat0d580581995-07-20 02:43:20 -050016
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050017#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050018
Glenn Randers-Pehrsonc3cd22b2010-03-08 21:10:25 -060019#ifdef PNG_READ_SUPPORTED
20
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050021# define png_strtod(p,a,b) strtod(a,b)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060022png_uint_32 PNGAPI
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050023png_get_uint_31(png_structp png_ptr, png_bytep buf)
24{
25 png_uint_32 i = png_get_uint_32(buf);
26 if (i > PNG_UINT_31_MAX)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060027 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050028 return (i);
29}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050030#ifndef PNG_USE_READ_MACROS
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050031/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050032png_uint_32 (PNGAPI
33png_get_uint_32)(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050034{
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060035 png_uint_32 i =
36 ((png_uint_32)(*(buf )) << 24) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060037 ((png_uint_32)(*(buf + 1)) << 16) +
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -060038 ((png_uint_32)(*(buf + 2)) << 8) +
39 ((png_uint_32)(*(buf + 3)) ) ;
Guy Schalnat0d580581995-07-20 02:43:20 -050040
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060041 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050042}
43
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050044/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050045 * data is stored in the PNG file in two's complement format, and it is
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050046 * assumed that the machine format for signed integers is the same.
47 */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050048png_int_32 (PNGAPI
49png_get_int_32)(png_bytep buf)
Andreas Dilger47a0c421997-05-16 02:46:07 -050050{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050051 png_int_32 i = ((png_int_32)(*buf) << 24) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060052 ((png_int_32)(*(buf + 1)) << 16) +
53 ((png_int_32)(*(buf + 2)) << 8) +
54 (png_int_32)(*(buf + 3));
Andreas Dilger47a0c421997-05-16 02:46:07 -050055
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060056 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050057}
Andreas Dilger47a0c421997-05-16 02:46:07 -050058
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050059/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5eb5cce2010-04-17 08:45:57 -050060png_uint_16 (PNGAPI
61png_get_uint_16)(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050062{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050063 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060064 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050065
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060066 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050067}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050068#endif /* PNG_USE_READ_MACROS */
Guy Schalnat0d580581995-07-20 02:43:20 -050069
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050070/* Read the chunk header (length + type name).
71 * Put the type name into png_ptr->chunk_name, and return the length.
72 */
73png_uint_32 /* PRIVATE */
74png_read_chunk_header(png_structp png_ptr)
75{
76 png_byte buf[8];
77 png_uint_32 length;
78
79#ifdef PNG_IO_STATE_SUPPORTED
80 /* Inform the I/O callback that the chunk header is being read.
81 * PNG_IO_CHUNK_HDR requires a single I/O call.
82 */
83 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
84#endif
85
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050086 /* Read the length and the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050087 png_read_data(png_ptr, buf, 8);
88 length = png_get_uint_31(png_ptr, buf);
89
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050090 /* Put the chunk name into png_ptr->chunk_name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050091 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
92
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -060093 png_debug2(0, "Reading %s chunk, length = %u",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -060094 png_ptr->chunk_name, length);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050095
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050096 /* Reset the crc and run it over the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050097 png_reset_crc(png_ptr);
98 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
99
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500100 /* Check to see if chunk name is valid */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500101 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
102
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500103#ifdef PNG_IO_STATE_SUPPORTED
104 /* Inform the I/O callback that chunk data will (possibly) be read.
105 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
106 */
107 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
108#endif
109
110 return length;
111}
112
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500113/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500114void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500115png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500116{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500117 if (png_ptr == NULL)
118 return;
Guy Schalnat6d764711995-12-19 03:22:19 -0600119 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500120 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500121}
122
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600123/* Optionally skip data and then check the CRC. Depending on whether we
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500124 * are reading a ancillary or critical chunk, and how the program has set
125 * things up, we may calculate the CRC on the data and print a message.
126 * Returns '1' if there was a CRC error, '0' otherwise.
127 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500128int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600129png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500130{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500131 png_size_t i;
132 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500133
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500134 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600135 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500136 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500137 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500138 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500139 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500140 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500141 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600142
Andreas Dilger47a0c421997-05-16 02:46:07 -0500143 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500145 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500146 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500147 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600148 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600149 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600150 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600151 }
152 else
153 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500154 png_chunk_benign_error(png_ptr, "CRC error");
155 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600156 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600157 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600158 }
159
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600160 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500161}
162
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600163/* Compare the CRC stored in the PNG file with that calculated by libpng from
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500164 * the data it has read thus far.
165 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500166int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600167png_crc_error(png_structp png_ptr)
168{
169 png_byte crc_bytes[4];
170 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500171 int need_crc = 1;
172
173 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
174 {
175 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
176 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
177 need_crc = 0;
178 }
179 else /* critical */
180 {
181 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
182 need_crc = 0;
183 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600184
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500185#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500186 /* Inform the I/O callback that the chunk CRC is being read */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500187 /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */
188 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
189#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500190
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600191 png_read_data(png_ptr, crc_bytes, 4);
192
Andreas Dilger47a0c421997-05-16 02:46:07 -0500193 if (need_crc)
194 {
195 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600196 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500197 }
198 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600199 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600200}
201
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600202#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500203 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600204static png_size_t
205png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600206 png_bytep output, png_size_t output_size)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600207{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600208 png_size_t count = 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600209
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600210 png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */
211 png_ptr->zstream.avail_in = size;
212
213 while (1)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600214 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600215 int ret, avail;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600216
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600217 /* Reset the output buffer each time round - we empty it
218 * after every inflate call.
219 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600220 png_ptr->zstream.next_out = png_ptr->zbuf;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600221 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600222
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600223 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
224 avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600225
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600226 /* First copy/count any new output - but only if we didn't
227 * get an error code.
228 */
229 if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600230 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600231 if (output != 0 && output_size > count)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600232 {
233 int copy = output_size - count;
234 if (avail < copy)
235 copy = avail;
236 png_memcpy(output + count, png_ptr->zbuf, copy);
237 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600238 count += avail;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600239 }
240
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600241 if (ret == Z_OK)
242 continue;
243
244 /* Termination conditions - always reset the zstream, it
245 * must be left in inflateInit state.
246 */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600247 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600248 inflateReset(&png_ptr->zstream);
249
250 if (ret == Z_STREAM_END)
251 return count; /* NOTE: may be zero. */
252
253 /* Now handle the error codes - the API always returns 0
254 * and the error message is dumped into the uncompressed
255 * buffer if available.
256 */
257 {
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600258 char *msg;
259#ifdef PNG_CONSOLE_IO_SUPPORTED
260 char umsg[52];
261#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600262 if (png_ptr->zstream.msg != 0)
263 msg = png_ptr->zstream.msg;
264 else
265 {
Glenn Randers-Pehrson6a9e4802010-02-19 09:47:43 -0600266#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600267 switch (ret)
268 {
269 case Z_BUF_ERROR:
270 msg = "Buffer error in compressed datastream in %s chunk";
271 break;
272 case Z_DATA_ERROR:
273 msg = "Data error in compressed datastream in %s chunk";
274 break;
275 default:
276 msg = "Incomplete compressed datastream in %s chunk";
277 break;
278 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600279
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600280 png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
281 msg = umsg;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600282#else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600283 msg = "Damaged compressed datastream in chunk other than IDAT";
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600284#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600285 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600286
287 png_warning(png_ptr, msg);
288 }
289
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600290 /* 0 means an error - notice that this code simply ignores
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600291 * zero length compressed chunks as a result.
292 */
293 return 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600294 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600295}
296
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600297/*
298 * Decompress trailing data in a chunk. The assumption is that chunkdata
299 * points at an allocated area holding the contents of a chunk with a
300 * trailing compressed part. What we get back is an allocated area
301 * holding the original prefix part and an uncompressed version of the
302 * trailing part (the malloc area passed in is freed).
303 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500304void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500305png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600306 png_size_t chunklength,
307 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600308{
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600309 /* The caller should guarantee this */
310 if (prefix_size > chunklength)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600311 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600312 /* The recovery is to delete the chunk. */
313 png_warning(png_ptr, "invalid chunklength");
314 prefix_size = 0; /* To delete everything */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600315 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600316
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600317 else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600318 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600319 png_size_t expanded_size = png_inflate(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600320 (png_bytep)(png_ptr->chunkdata + prefix_size),
321 chunklength - prefix_size,
322 0, /*output*/
323 0); /*output size*/
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600324
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600325 /* Now check the limits on this chunk - if the limit fails the
326 * compressed data will be removed, the prefix will remain.
327 */
328#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
329 if (png_ptr->user_chunk_malloc_max &&
330 (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600331#else
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600332# ifdef PNG_USER_CHUNK_MALLOC_MAX
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600333 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
334 prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600335# endif
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600336#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600337 png_warning(png_ptr, "Exceeded size limit while expanding chunk");
338
339 /* If the size is zero either there was an error and a message
340 * has already been output (warning) or the size really is zero
341 * and we have nothing to do - the code will exit through the
342 * error case below.
343 */
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600344#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
345 defined(PNG_USER_CHUNK_MALLOC_MAX)
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600346 else if (expanded_size > 0)
Glenn Randers-Pehrsonafa999d2010-03-09 07:52:30 -0600347#else
348 if (expanded_size > 0)
349#endif
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600350 {
351 /* Success (maybe) - really uncompress the chunk. */
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600352 png_size_t new_size = 0;
353 png_charp text = png_malloc_warn(png_ptr,
354 prefix_size + expanded_size + 1);
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600355
356 if (text != NULL)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600357 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600358 png_memcpy(text, png_ptr->chunkdata, prefix_size);
359 new_size = png_inflate(png_ptr,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600360 (png_bytep)(png_ptr->chunkdata + prefix_size),
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600361 chunklength - prefix_size,
Glenn Randers-Pehrsonee4eb9a2010-02-12 20:30:45 -0600362 (png_bytep)(text + prefix_size), expanded_size);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600363 text[prefix_size + expanded_size] = 0; /* just in case */
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600364
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600365 if (new_size == expanded_size)
366 {
367 png_free(png_ptr, png_ptr->chunkdata);
368 png_ptr->chunkdata = text;
369 *newlength = prefix_size + expanded_size;
370 return; /* The success return! */
371 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600372
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600373 png_warning(png_ptr, "png_inflate logic error");
374 png_free(png_ptr, text);
375 }
376 else
377 png_warning(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600378 }
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600379 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600380
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600381 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
382 {
Glenn Randers-Pehrsond7da8bb2010-03-13 20:30:10 -0600383#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600384 char umsg[50];
385
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600386 png_snprintf(umsg, sizeof umsg,
387 "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600388 png_warning(png_ptr, umsg);
389#else
390 png_warning(png_ptr, "Unknown zTXt compression type");
391#endif
392
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600393 /* The recovery is to simply drop the data. */
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600394 }
395
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600396 /* Generic error return - leave the prefix, delete the compressed
397 * data, reallocate the chunkdata to remove the potentially large
398 * amount of compressed data.
399 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600400 {
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600401 png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
402 if (text != NULL)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600403 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600404 if (prefix_size > 0)
Glenn Randers-Pehrson7d1f5912010-02-11 23:03:26 -0600405 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600406 png_free(png_ptr, png_ptr->chunkdata);
407 png_ptr->chunkdata = text;
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600408
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600409 /* This is an extra zero in the 'uncompressed' part. */
410 *(png_ptr->chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500411 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600412 /* Ignore a malloc error here - it is safe. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600413 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600414
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600415 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600416}
417#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600418
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500419/* Read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500420void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600421png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500422{
423 png_byte buf[13];
424 png_uint_32 width, height;
425 int bit_depth, color_type, compression_type, filter_type;
426 int interlace_type;
427
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500428 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500429
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600430 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500431 png_error(png_ptr, "Out of place IHDR");
432
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500433 /* Check the length */
Guy Schalnat0d580581995-07-20 02:43:20 -0500434 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600435 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500436
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600437 png_ptr->mode |= PNG_HAVE_IHDR;
438
Guy Schalnat0d580581995-07-20 02:43:20 -0500439 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600440 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500441
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500442 width = png_get_uint_31(png_ptr, buf);
443 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500444 bit_depth = buf[8];
445 color_type = buf[9];
446 compression_type = buf[10];
447 filter_type = buf[11];
448 interlace_type = buf[12];
449
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500450 /* Set internal variables */
Guy Schalnat0d580581995-07-20 02:43:20 -0500451 png_ptr->width = width;
452 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600453 png_ptr->bit_depth = (png_byte)bit_depth;
454 png_ptr->interlaced = (png_byte)interlace_type;
455 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500456#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600457 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500458#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500459 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500460
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500461 /* Find number of channels */
Guy Schalnat0d580581995-07-20 02:43:20 -0500462 switch (png_ptr->color_type)
463 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500464 case PNG_COLOR_TYPE_GRAY:
465 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 png_ptr->channels = 1;
467 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500468
Andreas Dilger47a0c421997-05-16 02:46:07 -0500469 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500470 png_ptr->channels = 3;
471 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500472
Andreas Dilger47a0c421997-05-16 02:46:07 -0500473 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500474 png_ptr->channels = 2;
475 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500476
Andreas Dilger47a0c421997-05-16 02:46:07 -0500477 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500478 png_ptr->channels = 4;
479 break;
480 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600481
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500482 /* Set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600483 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600484 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500485 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500486 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
487 png_debug1(3, "channels = %d", png_ptr->channels);
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -0600488 png_debug1(3, "rowbytes = %u", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500489 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600490 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500491}
492
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500493/* Read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500494void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600495png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500496{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600497 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600498 int num, i;
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500499#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500500 png_colorp pal_ptr;
501#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500502
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500503 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500504
Guy Schalnate5a37791996-06-05 15:50:50 -0500505 if (!(png_ptr->mode & PNG_HAVE_IHDR))
506 png_error(png_ptr, "Missing IHDR before PLTE");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500507
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600508 else if (png_ptr->mode & PNG_HAVE_IDAT)
509 {
510 png_warning(png_ptr, "Invalid PLTE after IDAT");
511 png_crc_finish(png_ptr, length);
512 return;
513 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500514
Guy Schalnate5a37791996-06-05 15:50:50 -0500515 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600516 png_error(png_ptr, "Duplicate PLTE chunk");
517
518 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500519
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500520 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
521 {
522 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600523 "Ignoring PLTE chunk in grayscale PNG");
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500524 png_crc_finish(png_ptr, length);
525 return;
526 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500527#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500528 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
529 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600530 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500531 return;
532 }
533#endif
534
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600535 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500536 {
537 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
538 {
539 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600540 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500541 return;
542 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500543
Guy Schalnate5a37791996-06-05 15:50:50 -0500544 else
545 {
546 png_error(png_ptr, "Invalid palette chunk");
547 }
548 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500549
550 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500551
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500552#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500553 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
554 {
555 png_byte buf[3];
556
557 png_crc_read(png_ptr, buf, 3);
558 pal_ptr->red = buf[0];
559 pal_ptr->green = buf[1];
560 pal_ptr->blue = buf[2];
561 }
562#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600563 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500564 {
565 png_byte buf[3];
566
567 png_crc_read(png_ptr, buf, 3);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500568 /* Don't depend upon png_color being any order */
Guy Schalnat0d580581995-07-20 02:43:20 -0500569 palette[i].red = buf[0];
570 palette[i].green = buf[1];
571 palette[i].blue = buf[2];
572 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500573#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600574
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600575 /* 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 -0500576 * whatever the normal CRC configuration tells us. However, if we
577 * have an RGB image, the PLTE can be considered ancillary, so
578 * we will act as though it is.
579 */
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500580#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600581 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600582#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600583 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500584 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600585 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500586#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600587 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
588 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600589 /* If we don't want to use the data from an ancillary chunk,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600590 * we have two options: an error abort, or a warning and we
591 * ignore the data in this chunk (which should be OK, since
592 * it's considered ancillary for a RGB or RGBA image).
593 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600594 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
595 {
596 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
597 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500598 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600599 }
600 else
601 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600602 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600603 return;
604 }
605 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500606 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600607 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
608 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600609 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600610 }
611 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600612#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500613
Andreas Dilger47a0c421997-05-16 02:46:07 -0500614 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500615
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500616#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500617 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
618 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600619 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500620 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500621 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500622 {
623 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500624 png_ptr->num_trans = (png_uint_16)num;
625 }
626 if (info_ptr->num_trans > (png_uint_16)num)
627 {
628 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
629 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500630 }
631 }
632 }
633#endif
634
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600635}
Guy Schalnate5a37791996-06-05 15:50:50 -0500636
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500637void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600638png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
639{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500640 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500641
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600642 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
643 {
644 png_error(png_ptr, "No image in file");
645 }
646
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600647 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600648
649 if (length != 0)
650 {
651 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500653 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500654
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500655 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500656}
657
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500658#ifdef PNG_READ_gAMA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500659void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600660png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500661{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600662 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600663#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500664 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600665#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500666 png_byte buf[4];
667
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500668 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500669
Guy Schalnate5a37791996-06-05 15:50:50 -0500670 if (!(png_ptr->mode & PNG_HAVE_IHDR))
671 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600672 else if (png_ptr->mode & PNG_HAVE_IDAT)
673 {
674 png_warning(png_ptr, "Invalid gAMA after IDAT");
675 png_crc_finish(png_ptr, length);
676 return;
677 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500678 else if (png_ptr->mode & PNG_HAVE_PLTE)
679 /* Should be an error, but we can cope with it */
680 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600681
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500682 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500683#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600684 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600685#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600686 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600687 {
688 png_warning(png_ptr, "Duplicate gAMA chunk");
689 png_crc_finish(png_ptr, length);
690 return;
691 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500692
Guy Schalnat0d580581995-07-20 02:43:20 -0500693 if (length != 4)
694 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600695 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600696 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500697 return;
698 }
699
700 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600701 if (png_crc_finish(png_ptr, 0))
702 return;
703
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600704 igamma = (png_fixed_point)png_get_uint_32(buf);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500705 /* Check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500706 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500707 {
708 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600709 "Ignoring gAMA chunk with gamma=0");
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500710 return;
711 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500712
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500713#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600714 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500715 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600716 {
717 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600718 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500719#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600720 fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600721#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600722 return;
723 }
724#endif /* PNG_READ_sRGB_SUPPORTED */
725
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600726#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600727 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600728# ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600729 png_ptr->gamma = file_gamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600730# endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600731 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600732#endif
733#ifdef PNG_FIXED_POINT_SUPPORTED
734 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
735#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500736}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500737#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500738
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500739#ifdef PNG_READ_sBIT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500740void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600741png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500742{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500743 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600744 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600745
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500746 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500747
Guy Schalnat69b14481996-01-10 02:56:49 -0600748 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500749
Guy Schalnate5a37791996-06-05 15:50:50 -0500750 if (!(png_ptr->mode & PNG_HAVE_IHDR))
751 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600752 else if (png_ptr->mode & PNG_HAVE_IDAT)
753 {
754 png_warning(png_ptr, "Invalid sBIT after IDAT");
755 png_crc_finish(png_ptr, length);
756 return;
757 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500758 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600759 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500760 /* Should be an error, but we can cope with it */
761 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600762 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500763 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600764 {
765 png_warning(png_ptr, "Duplicate sBIT chunk");
766 png_crc_finish(png_ptr, length);
767 return;
768 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500769
Guy Schalnat0d580581995-07-20 02:43:20 -0500770 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600771 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500772 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500773 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500774
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500775 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500776 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600777 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600778 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600779 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500780 }
781
Andreas Dilger47a0c421997-05-16 02:46:07 -0500782 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600783 if (png_crc_finish(png_ptr, 0))
784 return;
785
Guy Schalnat0d580581995-07-20 02:43:20 -0500786 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
787 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600788 png_ptr->sig_bit.red = buf[0];
789 png_ptr->sig_bit.green = buf[1];
790 png_ptr->sig_bit.blue = buf[2];
791 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500792 }
793 else
794 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600795 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600796 png_ptr->sig_bit.red = buf[0];
797 png_ptr->sig_bit.green = buf[0];
798 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600799 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500800 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500801 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500802}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500803#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500804
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500805#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500806void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600807png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500808{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500809 png_byte buf[32];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600810#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500811 float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600812#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600813 png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600814 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500815
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600816 png_uint_32 uint_x, uint_y;
817
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500818 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500819
Guy Schalnate5a37791996-06-05 15:50:50 -0500820 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600821 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600822 else if (png_ptr->mode & PNG_HAVE_IDAT)
823 {
824 png_warning(png_ptr, "Invalid cHRM after IDAT");
825 png_crc_finish(png_ptr, length);
826 return;
827 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500828 else if (png_ptr->mode & PNG_HAVE_PLTE)
829 /* Should be an error, but we can cope with it */
830 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600831
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500832 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500833#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600834 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600835#endif
836 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600837 {
838 png_warning(png_ptr, "Duplicate cHRM chunk");
839 png_crc_finish(png_ptr, length);
840 return;
841 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500842
Guy Schalnat0d580581995-07-20 02:43:20 -0500843 if (length != 32)
844 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600845 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600846 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600847 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500848 }
849
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500850 png_crc_read(png_ptr, buf, 32);
851 if (png_crc_finish(png_ptr, 0))
852 return;
853
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600854 uint_x = png_get_uint_32(buf);
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500855 uint_y = png_get_uint_32(buf + 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600856 int_x_white = (png_fixed_point)uint_x;
857 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500858
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500859 uint_x = png_get_uint_32(buf + 8);
860 uint_y = png_get_uint_32(buf + 12);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600861 int_x_red = (png_fixed_point)uint_x;
862 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500863
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500864 uint_x = png_get_uint_32(buf + 16);
865 uint_y = png_get_uint_32(buf + 20);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600866 int_x_green = (png_fixed_point)uint_x;
867 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500868
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500869 uint_x = png_get_uint_32(buf + 24);
870 uint_y = png_get_uint_32(buf + 28);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600871 int_x_blue = (png_fixed_point)uint_x;
872 int_y_blue = (png_fixed_point)uint_y;
873
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600874#ifdef PNG_FLOATING_POINT_SUPPORTED
875 white_x = (float)int_x_white / (float)100000.0;
876 white_y = (float)int_y_white / (float)100000.0;
877 red_x = (float)int_x_red / (float)100000.0;
878 red_y = (float)int_y_red / (float)100000.0;
879 green_x = (float)int_x_green / (float)100000.0;
880 green_y = (float)int_y_green / (float)100000.0;
881 blue_x = (float)int_x_blue / (float)100000.0;
882 blue_y = (float)int_y_blue / (float)100000.0;
883#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600884
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500885#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500886 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600887 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500888 if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
889 PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
890 PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
891 PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
892 PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
893 PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
894 PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
895 PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600896 {
897 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600898 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500899#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600900#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500901 fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600902 white_x, white_y, red_x, red_y);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500903 fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600904 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600905#else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500906 fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson3cd7cff2010-04-16 19:27:08 -0500907 (long)int_x_white, (long)int_y_white,
908 (long)int_x_red, (long)int_y_red);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500909 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson3cd7cff2010-04-16 19:27:08 -0500910 (long)int_x_green, (long)int_y_green,
911 (long)int_x_blue, (long)int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600912#endif
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500913#endif /* PNG_CONSOLE_IO_SUPPORTED */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600914 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600915 return;
916 }
917#endif /* PNG_READ_sRGB_SUPPORTED */
918
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600919#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500920 png_set_cHRM(png_ptr, info_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600921 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600922#endif
923#ifdef PNG_FIXED_POINT_SUPPORTED
924 png_set_cHRM_fixed(png_ptr, info_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600925 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
926 int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600927#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500928}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500929#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500930
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500931#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500932void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600933png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
934{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600935 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600936 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600937
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500938 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600939
940 if (!(png_ptr->mode & PNG_HAVE_IHDR))
941 png_error(png_ptr, "Missing IHDR before sRGB");
942 else if (png_ptr->mode & PNG_HAVE_IDAT)
943 {
944 png_warning(png_ptr, "Invalid sRGB after IDAT");
945 png_crc_finish(png_ptr, length);
946 return;
947 }
948 else if (png_ptr->mode & PNG_HAVE_PLTE)
949 /* Should be an error, but we can cope with it */
950 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600951
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500952 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600953 {
954 png_warning(png_ptr, "Duplicate sRGB chunk");
955 png_crc_finish(png_ptr, length);
956 return;
957 }
958
959 if (length != 1)
960 {
961 png_warning(png_ptr, "Incorrect sRGB chunk length");
962 png_crc_finish(png_ptr, length);
963 return;
964 }
965
966 png_crc_read(png_ptr, buf, 1);
967 if (png_crc_finish(png_ptr, 0))
968 return;
969
970 intent = buf[0];
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500971 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600972 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600973 {
974 png_warning(png_ptr, "Unknown sRGB intent");
975 return;
976 }
977
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600978#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600979 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600980 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500981 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600982#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500983 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600984#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600985# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500986 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600987# endif
988#endif
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500989 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600990 {
991 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600992 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500993#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600994# ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500995 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600996 (int)png_ptr->int_gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600997# else
998# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500999 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001000# endif
1001# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001002#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001003 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001004 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001005#endif /* PNG_READ_gAMA_SUPPORTED */
1006
1007#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001008#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001009 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -05001010 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
1011 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
1012 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
1013 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
1014 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
1015 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
1016 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
1017 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001018 {
1019 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001020 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001021 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001022#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001023#endif /* PNG_READ_cHRM_SUPPORTED */
1024
1025 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1026}
1027#endif /* PNG_READ_sRGB_SUPPORTED */
1028
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001029#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001030void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001031png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1032/* Note: this does not properly handle chunks that are > 64K under DOS */
1033{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001034 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001035 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001036 png_charp profile;
1037 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001038 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001039 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001040
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001041 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001042
1043 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1044 png_error(png_ptr, "Missing IHDR before iCCP");
1045 else if (png_ptr->mode & PNG_HAVE_IDAT)
1046 {
1047 png_warning(png_ptr, "Invalid iCCP after IDAT");
1048 png_crc_finish(png_ptr, length);
1049 return;
1050 }
1051 else if (png_ptr->mode & PNG_HAVE_PLTE)
1052 /* Should be an error, but we can cope with it */
1053 png_warning(png_ptr, "Out of place iCCP chunk");
1054
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001055 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001056 {
1057 png_warning(png_ptr, "Duplicate iCCP chunk");
1058 png_crc_finish(png_ptr, length);
1059 return;
1060 }
1061
1062#ifdef PNG_MAX_MALLOC_64K
1063 if (length > (png_uint_32)65535L)
1064 {
1065 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1066 skip = length - (png_uint_32)65535L;
1067 length = (png_uint_32)65535L;
1068 }
1069#endif
1070
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001071 png_free(png_ptr, png_ptr->chunkdata);
1072 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001073 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001074 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001075
1076 if (png_crc_finish(png_ptr, skip))
1077 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001078 png_free(png_ptr, png_ptr->chunkdata);
1079 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001080 return;
1081 }
1082
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001083 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001084
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001085 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001086 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001087
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001088 ++profile;
1089
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001090 /* There should be at least one zero (the compression type byte)
1091 * following the separator, and we should be on it
1092 */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001093 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001094 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001095 png_free(png_ptr, png_ptr->chunkdata);
1096 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001097 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001098 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001099 }
1100
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001101 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001102 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001103 if (compression_type)
1104 {
1105 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001106 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001107 wrote nonzero) */
1108 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001109
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001110 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001111 png_decompress_chunk(png_ptr, compression_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001112 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001113
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001114 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001115
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001116 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001117 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001118 png_free(png_ptr, png_ptr->chunkdata);
1119 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001120 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1121 return;
1122 }
1123
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001124 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001125 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001126 profile_size = ((*(pC )) << 24) |
1127 ((*(pC + 1)) << 16) |
1128 ((*(pC + 2)) << 8) |
1129 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001130
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001131 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001132 profile_length = profile_size;
1133
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001134 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001135 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001136 png_free(png_ptr, png_ptr->chunkdata);
1137 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001138#ifdef PNG_STDIO_SUPPORTED
1139 {
Glenn Randers-Pehrson92a3ef42010-03-31 21:50:21 -05001140 char umsg[80];
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001141
Glenn Randers-Pehrson92a3ef42010-03-31 21:50:21 -05001142 png_snprintf2(umsg, 80,
1143 "Ignoring iCCP chunk with declared size = %lu "
1144 "and actual length = %lu",
1145 (unsigned long)profile_size,
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001146 (unsigned long)profile_length);
1147 png_warning(png_ptr, umsg);
1148 }
1149#endif
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001150 return;
1151 }
1152
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001153 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001154 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001155 png_free(png_ptr, png_ptr->chunkdata);
1156 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001157}
1158#endif /* PNG_READ_iCCP_SUPPORTED */
1159
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001160#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001161void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001162png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1163/* Note: this does not properly handle chunks that are > 64K under DOS */
1164{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001165 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001166 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001167#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001168 png_sPLT_entryp pp;
1169#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001170 int data_length, entry_size, i;
1171 png_uint_32 skip = 0;
1172 png_size_t slength;
1173
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001174 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001175
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001176#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001177
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001178 if (png_ptr->user_chunk_cache_max != 0)
1179 {
1180 if (png_ptr->user_chunk_cache_max == 1)
1181 {
1182 png_crc_finish(png_ptr, length);
1183 return;
1184 }
1185 if (--png_ptr->user_chunk_cache_max == 1)
1186 {
1187 png_warning(png_ptr, "No space in chunk cache for sPLT");
1188 png_crc_finish(png_ptr, length);
1189 return;
1190 }
1191 }
1192#endif
1193
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001194 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1195 png_error(png_ptr, "Missing IHDR before sPLT");
1196 else if (png_ptr->mode & PNG_HAVE_IDAT)
1197 {
1198 png_warning(png_ptr, "Invalid sPLT after IDAT");
1199 png_crc_finish(png_ptr, length);
1200 return;
1201 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001202
1203#ifdef PNG_MAX_MALLOC_64K
1204 if (length > (png_uint_32)65535L)
1205 {
1206 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1207 skip = length - (png_uint_32)65535L;
1208 length = (png_uint_32)65535L;
1209 }
1210#endif
1211
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001212 png_free(png_ptr, png_ptr->chunkdata);
1213 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001214 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001215 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001216
1217 if (png_crc_finish(png_ptr, skip))
1218 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001219 png_free(png_ptr, png_ptr->chunkdata);
1220 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001221 return;
1222 }
1223
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001224 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001225
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001226 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1227 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001228 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001229 ++entry_start;
1230
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001231 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001232 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001233 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001234 png_free(png_ptr, png_ptr->chunkdata);
1235 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001236 png_warning(png_ptr, "malformed sPLT chunk");
1237 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001238 }
1239
1240 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001241 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001242 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001243
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001244 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001245 if (data_length % entry_size)
1246 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001247 png_free(png_ptr, png_ptr->chunkdata);
1248 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001249 png_warning(png_ptr, "sPLT chunk has bad length");
1250 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001251 }
1252
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001253 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001254 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001255 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001256 {
1257 png_warning(png_ptr, "sPLT chunk too long");
1258 return;
1259 }
1260 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001261 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001262 if (new_palette.entries == NULL)
1263 {
1264 png_warning(png_ptr, "sPLT chunk requires too much memory");
1265 return;
1266 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001267
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001268#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001269 for (i = 0; i < new_palette.nentries; i++)
1270 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001271 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001272
1273 if (new_palette.depth == 8)
1274 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001275 pp->red = *entry_start++;
1276 pp->green = *entry_start++;
1277 pp->blue = *entry_start++;
1278 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001279 }
1280 else
1281 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001282 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1283 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1284 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1285 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001286 }
1287 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1288 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001289#else
1290 pp = new_palette.entries;
1291 for (i = 0; i < new_palette.nentries; i++)
1292 {
1293
1294 if (new_palette.depth == 8)
1295 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001296 pp[i].red = *entry_start++;
1297 pp[i].green = *entry_start++;
1298 pp[i].blue = *entry_start++;
1299 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001300 }
1301 else
1302 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001303 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1304 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1305 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1306 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001307 }
1308 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1309 }
1310#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001311
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001312 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001313 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001314
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001315 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001316
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001317 png_free(png_ptr, png_ptr->chunkdata);
1318 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001319 png_free(png_ptr, new_palette.entries);
1320}
1321#endif /* PNG_READ_sPLT_SUPPORTED */
1322
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001323#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001324void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001325png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001326{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001327 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001328
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001329 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001330
Guy Schalnate5a37791996-06-05 15:50:50 -05001331 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1332 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001333 else if (png_ptr->mode & PNG_HAVE_IDAT)
1334 {
1335 png_warning(png_ptr, "Invalid tRNS after IDAT");
1336 png_crc_finish(png_ptr, length);
1337 return;
1338 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001339 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001340 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001341 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001342 png_crc_finish(png_ptr, length);
1343 return;
1344 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001345
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001346 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001347 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001348 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001349
1350 if (length != 2)
1351 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001352 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001353 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001354 return;
1355 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001356
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001357 png_crc_read(png_ptr, buf, 2);
1358 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001359 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001360 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001361 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1362 {
1363 png_byte buf[6];
1364
1365 if (length != 6)
1366 {
1367 png_warning(png_ptr, "Incorrect tRNS chunk length");
1368 png_crc_finish(png_ptr, length);
1369 return;
1370 }
1371 png_crc_read(png_ptr, buf, (png_size_t)length);
1372 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001373 png_ptr->trans_color.red = png_get_uint_16(buf);
1374 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1375 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001376 }
1377 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1378 {
1379 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1380 {
1381 /* Should be an error, but we can cope with it. */
1382 png_warning(png_ptr, "Missing PLTE before tRNS");
1383 }
1384 if (length > (png_uint_32)png_ptr->num_palette ||
1385 length > PNG_MAX_PALETTE_LENGTH)
1386 {
1387 png_warning(png_ptr, "Incorrect tRNS chunk length");
1388 png_crc_finish(png_ptr, length);
1389 return;
1390 }
1391 if (length == 0)
1392 {
1393 png_warning(png_ptr, "Zero length tRNS chunk");
1394 png_crc_finish(png_ptr, length);
1395 return;
1396 }
1397 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1398 png_ptr->num_trans = (png_uint_16)length;
1399 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001400 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001401 {
1402 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001403 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001404 return;
1405 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001406
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001407 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001408 {
1409 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001410 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001411 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001412
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001413 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001414 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001415}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001416#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001417
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001418#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001419void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001420png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001421{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001422 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001423 png_byte buf[6];
1424
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001425 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001426
Guy Schalnate5a37791996-06-05 15:50:50 -05001427 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1428 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001429 else if (png_ptr->mode & PNG_HAVE_IDAT)
1430 {
1431 png_warning(png_ptr, "Invalid bKGD after IDAT");
1432 png_crc_finish(png_ptr, length);
1433 return;
1434 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001435 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001436 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001437 {
1438 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001439 png_crc_finish(png_ptr, length);
1440 return;
1441 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001442 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001443 {
1444 png_warning(png_ptr, "Duplicate bKGD chunk");
1445 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001446 return;
1447 }
1448
Guy Schalnat0d580581995-07-20 02:43:20 -05001449 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1450 truelen = 1;
1451 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1452 truelen = 6;
1453 else
1454 truelen = 2;
1455
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001456 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001457 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001458 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001459 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001460 return;
1461 }
1462
Andreas Dilger47a0c421997-05-16 02:46:07 -05001463 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001464 if (png_crc_finish(png_ptr, 0))
1465 return;
1466
Guy Schalnate5a37791996-06-05 15:50:50 -05001467 /* We convert the index value into RGB components so that we can allow
1468 * arbitrary RGB values for background when we have transparency, and
1469 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001470 * from the info_ptr struct.
1471 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001472 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001473 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001474 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001475 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001476 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001477 if (buf[0] >= info_ptr->num_palette)
1478 {
1479 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1480 return;
1481 }
1482 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001483 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001484 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001485 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001486 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001487 (png_uint_16)png_ptr->palette[buf[0]].blue;
1488 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001489 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001490 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001491 {
1492 png_ptr->background.red =
1493 png_ptr->background.green =
1494 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001495 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001496 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001497 else
1498 {
1499 png_ptr->background.red = png_get_uint_16(buf);
1500 png_ptr->background.green = png_get_uint_16(buf + 2);
1501 png_ptr->background.blue = png_get_uint_16(buf + 4);
1502 }
1503
Andreas Dilger47a0c421997-05-16 02:46:07 -05001504 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001505}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001506#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001507
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001508#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001509void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001510png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001511{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001512 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001513 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001514
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001515 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001516
Guy Schalnate5a37791996-06-05 15:50:50 -05001517 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1518 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001519 else if (png_ptr->mode & PNG_HAVE_IDAT)
1520 {
1521 png_warning(png_ptr, "Invalid hIST after IDAT");
1522 png_crc_finish(png_ptr, length);
1523 return;
1524 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001525 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1526 {
1527 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001528 png_crc_finish(png_ptr, length);
1529 return;
1530 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001531 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001532 {
1533 png_warning(png_ptr, "Duplicate hIST chunk");
1534 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001535 return;
1536 }
1537
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001538 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001539 if (num != (unsigned int) png_ptr->num_palette || num >
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001540 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001541 {
1542 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001543 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001544 return;
1545 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001546
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001547 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001548 {
1549 png_byte buf[2];
1550
1551 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001552 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001553 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001554
1555 if (png_crc_finish(png_ptr, 0))
1556 return;
1557
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001558 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001559}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001560#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001561
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001562#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001563void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001564png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001565{
1566 png_byte buf[9];
1567 png_uint_32 res_x, res_y;
1568 int unit_type;
1569
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001570 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001571
Guy Schalnate5a37791996-06-05 15:50:50 -05001572 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001573 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001574 else if (png_ptr->mode & PNG_HAVE_IDAT)
1575 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001576 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001577 png_crc_finish(png_ptr, length);
1578 return;
1579 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001580 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001581 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001582 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001583 png_crc_finish(png_ptr, length);
1584 return;
1585 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001586
Guy Schalnat0d580581995-07-20 02:43:20 -05001587 if (length != 9)
1588 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001589 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001590 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001591 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001592 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001593
1594 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001595 if (png_crc_finish(png_ptr, 0))
1596 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001597
1598 res_x = png_get_uint_32(buf);
1599 res_y = png_get_uint_32(buf + 4);
1600 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001601 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001602}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001603#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001604
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001605#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001606void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001607png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001608{
1609 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001610 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001611 int unit_type;
1612
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001613 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001614
Guy Schalnate5a37791996-06-05 15:50:50 -05001615 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1616 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001617 else if (png_ptr->mode & PNG_HAVE_IDAT)
1618 {
1619 png_warning(png_ptr, "Invalid oFFs after IDAT");
1620 png_crc_finish(png_ptr, length);
1621 return;
1622 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001623 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001624 {
1625 png_warning(png_ptr, "Duplicate oFFs chunk");
1626 png_crc_finish(png_ptr, length);
1627 return;
1628 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001629
Guy Schalnat0d580581995-07-20 02:43:20 -05001630 if (length != 9)
1631 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001632 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001633 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001634 return;
1635 }
1636
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001637 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001638 if (png_crc_finish(png_ptr, 0))
1639 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001640
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001641 offset_x = png_get_int_32(buf);
1642 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001643 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001644 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1645}
1646#endif
1647
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001648#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001649/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001650void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001651png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1652{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001653 png_int_32 X0, X1;
1654 png_byte type, nparams;
1655 png_charp buf, units, endptr;
1656 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001657 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001658 int i;
1659
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001660 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001661
1662 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1663 png_error(png_ptr, "Missing IHDR before pCAL");
1664 else if (png_ptr->mode & PNG_HAVE_IDAT)
1665 {
1666 png_warning(png_ptr, "Invalid pCAL after IDAT");
1667 png_crc_finish(png_ptr, length);
1668 return;
1669 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001670 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001671 {
1672 png_warning(png_ptr, "Duplicate pCAL chunk");
1673 png_crc_finish(png_ptr, length);
1674 return;
1675 }
1676
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001677 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001678 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001679 png_free(png_ptr, png_ptr->chunkdata);
1680 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1681 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001682 {
1683 png_warning(png_ptr, "No memory for pCAL purpose");
1684 return;
1685 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001686 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001687 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001688
1689 if (png_crc_finish(png_ptr, 0))
1690 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001691 png_free(png_ptr, png_ptr->chunkdata);
1692 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001693 return;
1694 }
1695
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001696 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001697
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001698 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001699 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001700 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001701
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001702 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001703
1704 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001705 * in order to get the parameter information.
1706 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001707 if (endptr <= buf + 12)
1708 {
1709 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001710 png_free(png_ptr, png_ptr->chunkdata);
1711 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001712 return;
1713 }
1714
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001715 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001716 X0 = png_get_int_32((png_bytep)buf+1);
1717 X1 = png_get_int_32((png_bytep)buf+5);
1718 type = buf[9];
1719 nparams = buf[10];
1720 units = buf + 11;
1721
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001722 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001723 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001724 * equation types.
1725 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001726 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1727 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1728 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1729 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1730 {
1731 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001732 png_free(png_ptr, png_ptr->chunkdata);
1733 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001734 return;
1735 }
1736 else if (type >= PNG_EQUATION_LAST)
1737 {
1738 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1739 }
1740
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001741 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001742 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001743
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001744 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001745 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001746 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001747 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001748 {
1749 png_free(png_ptr, png_ptr->chunkdata);
1750 png_ptr->chunkdata = NULL;
1751 png_warning(png_ptr, "No memory for pCAL params");
1752 return;
1753 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001754
1755 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001756 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001757 {
1758 buf++; /* Skip the null string terminator from previous parameter. */
1759
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001760 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001761 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001762 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001763
1764 /* Make sure we haven't run out of data yet */
1765 if (buf > endptr)
1766 {
1767 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001768 png_free(png_ptr, png_ptr->chunkdata);
1769 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001770 png_free(png_ptr, params);
1771 return;
1772 }
1773 }
1774
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001775 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001776 units, params);
1777
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001778 png_free(png_ptr, png_ptr->chunkdata);
1779 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001780 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001781}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001782#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001783
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001784#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001785/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001786void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001787png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1788{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001789 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001790#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001791 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001792 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001793#else
1794#ifdef PNG_FIXED_POINT_SUPPORTED
1795 png_charp swidth, sheight;
1796#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001797#endif
1798 png_size_t slength;
1799
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001800 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001801
1802 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1803 png_error(png_ptr, "Missing IHDR before sCAL");
1804 else if (png_ptr->mode & PNG_HAVE_IDAT)
1805 {
1806 png_warning(png_ptr, "Invalid sCAL after IDAT");
1807 png_crc_finish(png_ptr, length);
1808 return;
1809 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001810 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001811 {
1812 png_warning(png_ptr, "Duplicate sCAL chunk");
1813 png_crc_finish(png_ptr, length);
1814 return;
1815 }
1816
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001817 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001818 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001819 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1820 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001821 {
1822 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1823 return;
1824 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001825 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001826 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001827
1828 if (png_crc_finish(png_ptr, 0))
1829 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001830 png_free(png_ptr, png_ptr->chunkdata);
1831 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001832 return;
1833 }
1834
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001835 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001836
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001837 ep = png_ptr->chunkdata + 1; /* Skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001838
1839#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001840 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001841 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001842 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001843 png_warning(png_ptr, "malformed width string in sCAL chunk");
1844 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001845 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001846#else
1847#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001848 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1849 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001850 {
1851 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1852 return;
1853 }
1854 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001855#endif
1856#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001857
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001858 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001859 /* Empty loop */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001860 ep++;
1861
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001862 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001863 {
1864 png_warning(png_ptr, "Truncated sCAL chunk");
1865#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1866 !defined(PNG_FLOATING_POINT_SUPPORTED)
1867 png_free(png_ptr, swidth);
1868#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001869 png_free(png_ptr, png_ptr->chunkdata);
1870 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001871 return;
1872 }
1873
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001874#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001875 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001876 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001877 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001878 png_warning(png_ptr, "malformed height string in sCAL chunk");
1879 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001880 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001881#else
1882#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001883 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001884 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001885 {
1886 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1887 return;
1888 }
1889 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001890#endif
1891#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001892
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001893 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001894#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001895 || width <= 0. || height <= 0.
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001896#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001897 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001898 {
1899 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001900 png_free(png_ptr, png_ptr->chunkdata);
1901 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001902#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001903 png_free(png_ptr, swidth);
1904 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001905#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001906 return;
1907 }
1908
1909
1910#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001911 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001912#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001913#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001914 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001915#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001916#endif
1917
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001918 png_free(png_ptr, png_ptr->chunkdata);
1919 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001920#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1921 png_free(png_ptr, swidth);
1922 png_free(png_ptr, sheight);
1923#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001924}
1925#endif
1926
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001927#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001928void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001929png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001930{
1931 png_byte buf[7];
1932 png_time mod_time;
1933
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001934 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001935
Guy Schalnate5a37791996-06-05 15:50:50 -05001936 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001937 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001938 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001939 {
1940 png_warning(png_ptr, "Duplicate tIME chunk");
1941 png_crc_finish(png_ptr, length);
1942 return;
1943 }
1944
1945 if (png_ptr->mode & PNG_HAVE_IDAT)
1946 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001947
Guy Schalnat0d580581995-07-20 02:43:20 -05001948 if (length != 7)
1949 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001950 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001951 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001952 return;
1953 }
1954
1955 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001956 if (png_crc_finish(png_ptr, 0))
1957 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001958
1959 mod_time.second = buf[6];
1960 mod_time.minute = buf[5];
1961 mod_time.hour = buf[4];
1962 mod_time.day = buf[3];
1963 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001964 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001965
Andreas Dilger47a0c421997-05-16 02:46:07 -05001966 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001967}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001968#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001969
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001970#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001971/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001972void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001973png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001974{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001975 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001976 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001977 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001978 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001979 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001980 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001981
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001982 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05001983
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001984#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001985 if (png_ptr->user_chunk_cache_max != 0)
1986 {
1987 if (png_ptr->user_chunk_cache_max == 1)
1988 {
1989 png_crc_finish(png_ptr, length);
1990 return;
1991 }
1992 if (--png_ptr->user_chunk_cache_max == 1)
1993 {
1994 png_warning(png_ptr, "No space in chunk cache for tEXt");
1995 png_crc_finish(png_ptr, length);
1996 return;
1997 }
1998 }
1999#endif
2000
Guy Schalnate5a37791996-06-05 15:50:50 -05002001 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2002 png_error(png_ptr, "Missing IHDR before tEXt");
2003
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002004 if (png_ptr->mode & PNG_HAVE_IDAT)
2005 png_ptr->mode |= PNG_AFTER_IDAT;
2006
Andreas Dilger47a0c421997-05-16 02:46:07 -05002007#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002008 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002009 {
2010 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002011 skip = length - (png_uint_32)65535L;
2012 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002013 }
2014#endif
2015
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002016 png_free(png_ptr, png_ptr->chunkdata);
2017
2018 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2019 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002020 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002021 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002022 return;
2023 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002024 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002025 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002026
2027 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002028 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002029 png_free(png_ptr, png_ptr->chunkdata);
2030 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002031 return;
2032 }
2033
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002034 key = png_ptr->chunkdata;
2035
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002036 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002037
2038 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002039 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002040
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002041 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002042 text++;
2043
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002044 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002045 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002046 if (text_ptr == NULL)
2047 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002048 png_warning(png_ptr, "Not enough memory to process text chunk");
2049 png_free(png_ptr, png_ptr->chunkdata);
2050 png_ptr->chunkdata = NULL;
2051 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002052 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002053 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2054 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002055 text_ptr->lang = NULL;
2056 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002057 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002058 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002059 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002060
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002061 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002062
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002063 png_free(png_ptr, png_ptr->chunkdata);
2064 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002065 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002066 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002067 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002068}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002069#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002070
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002071#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002072/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002073void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002074png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002075{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002076 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002077 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002078 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002079 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002080 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002081
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002082 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002083
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002084#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002085 if (png_ptr->user_chunk_cache_max != 0)
2086 {
2087 if (png_ptr->user_chunk_cache_max == 1)
2088 {
2089 png_crc_finish(png_ptr, length);
2090 return;
2091 }
2092 if (--png_ptr->user_chunk_cache_max == 1)
2093 {
2094 png_warning(png_ptr, "No space in chunk cache for zTXt");
2095 png_crc_finish(png_ptr, length);
2096 return;
2097 }
2098 }
2099#endif
2100
Guy Schalnate5a37791996-06-05 15:50:50 -05002101 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2102 png_error(png_ptr, "Missing IHDR before zTXt");
2103
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002104 if (png_ptr->mode & PNG_HAVE_IDAT)
2105 png_ptr->mode |= PNG_AFTER_IDAT;
2106
Andreas Dilger47a0c421997-05-16 02:46:07 -05002107#ifdef PNG_MAX_MALLOC_64K
2108 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002109 * there is no hard and fast rule to tell us where to stop.
2110 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002111 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002112 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002113 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2114 png_crc_finish(png_ptr, length);
2115 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002116 }
2117#endif
2118
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002119 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002120 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2121 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002122 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002123 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2124 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002125 }
2126 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002127 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002128 if (png_crc_finish(png_ptr, 0))
2129 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002130 png_free(png_ptr, png_ptr->chunkdata);
2131 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002132 return;
2133 }
2134
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002135 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002136
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002137 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002138 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002139
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002140 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002141 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002142 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002143 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002144 png_free(png_ptr, png_ptr->chunkdata);
2145 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002146 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002147 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002148 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002149 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002150 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002151 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2152 {
2153 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2154 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2155 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002156 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002157 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002158 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002159
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002160 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002161 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002162
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-Pehrson07748d12002-05-25 11:12:10 -05002165 if (text_ptr == NULL)
2166 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002167 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2168 png_free(png_ptr, png_ptr->chunkdata);
2169 png_ptr->chunkdata = NULL;
2170 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002171 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002172 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002173 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002174 text_ptr->lang = NULL;
2175 text_ptr->lang_key = NULL;
2176 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002177 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002178 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002179
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002180 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002181
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002182 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002183 png_free(png_ptr, png_ptr->chunkdata);
2184 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002185 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002186 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002187}
2188#endif
2189
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002190#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002191/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002192void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002193png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2194{
2195 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002196 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002197 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002198 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002199 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002200 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002201
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002202 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002203
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002204#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002205 if (png_ptr->user_chunk_cache_max != 0)
2206 {
2207 if (png_ptr->user_chunk_cache_max == 1)
2208 {
2209 png_crc_finish(png_ptr, length);
2210 return;
2211 }
2212 if (--png_ptr->user_chunk_cache_max == 1)
2213 {
2214 png_warning(png_ptr, "No space in chunk cache for iTXt");
2215 png_crc_finish(png_ptr, length);
2216 return;
2217 }
2218 }
2219#endif
2220
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002221 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2222 png_error(png_ptr, "Missing IHDR before iTXt");
2223
2224 if (png_ptr->mode & PNG_HAVE_IDAT)
2225 png_ptr->mode |= PNG_AFTER_IDAT;
2226
2227#ifdef PNG_MAX_MALLOC_64K
2228 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002229 * there is no hard and fast rule to tell us where to stop.
2230 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002231 if (length > (png_uint_32)65535L)
2232 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002233 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2234 png_crc_finish(png_ptr, length);
2235 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002236 }
2237#endif
2238
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002239 png_free(png_ptr, png_ptr->chunkdata);
2240 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2241 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002242 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002243 png_warning(png_ptr, "No memory to process iTXt chunk");
2244 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002245 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002246 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002247 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002248 if (png_crc_finish(png_ptr, 0))
2249 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002250 png_free(png_ptr, png_ptr->chunkdata);
2251 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002252 return;
2253 }
2254
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002255 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002256
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002257 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002258 /* Empty loop */ ;
2259 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002260
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002261 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002262 * translated keyword (possibly empty), and possibly some text after the
2263 * keyword
2264 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002265
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002266 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002267 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002268 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002269 png_free(png_ptr, png_ptr->chunkdata);
2270 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002271 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002272 }
2273 else
2274 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002275 comp_flag = *lang++;
2276 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002277 }
2278
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002279 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002280 /* Empty loop */ ;
2281 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002282
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002283 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002284 {
2285 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002286 png_free(png_ptr, png_ptr->chunkdata);
2287 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002288 return;
2289 }
2290
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002291 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002292 /* Empty loop */ ;
2293 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002294 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002295 {
2296 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002297 png_free(png_ptr, png_ptr->chunkdata);
2298 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002299 return;
2300 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002301
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002302 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002303
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002304 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002305 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002306 png_decompress_chunk(png_ptr, comp_type,
2307 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002308 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002309 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002310 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002311 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002312 if (text_ptr == NULL)
2313 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002314 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2315 png_free(png_ptr, png_ptr->chunkdata);
2316 png_ptr->chunkdata = NULL;
2317 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002318 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002319 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002320 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2321 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002322 text_ptr->itxt_length = data_len;
2323 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002324 text_ptr->key = png_ptr->chunkdata;
2325 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002326
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002327 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002328
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002329 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002330 png_free(png_ptr, png_ptr->chunkdata);
2331 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002332 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002333 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002334}
2335#endif
2336
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002337/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002338 * chunk. If there isn't a problem with the chunk itself (ie bad
2339 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2340 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2341 * case it will be saved away to be written out later.
2342 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002343void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002344png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2345{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002346 png_uint_32 skip = 0;
2347
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002348 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002349
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002350#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002351 if (png_ptr->user_chunk_cache_max != 0)
2352 {
2353 if (png_ptr->user_chunk_cache_max == 1)
2354 {
2355 png_crc_finish(png_ptr, length);
2356 return;
2357 }
2358 if (--png_ptr->user_chunk_cache_max == 1)
2359 {
2360 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2361 png_crc_finish(png_ptr, length);
2362 return;
2363 }
2364 }
2365#endif
2366
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002367 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002368 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002369 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002370 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002371 png_ptr->mode |= PNG_AFTER_IDAT;
2372 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002373
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002374 if (!(png_ptr->chunk_name[0] & 0x20))
2375 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002376#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002377 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002378 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002379#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002380 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002381#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002382 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002383#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002384 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002385 }
2386
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002387#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002388 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002389#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002390 || (png_ptr->read_user_chunk_fn != NULL)
2391#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002392 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002393 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002394#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002395 if (length > (png_uint_32)65535L)
2396 {
2397 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2398 skip = length - (png_uint_32)65535L;
2399 length = (png_uint_32)65535L;
2400 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002401#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002402 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2403 (png_charp)png_ptr->chunk_name,
2404 png_sizeof(png_ptr->unknown_chunk.name));
2405 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2406 = '\0';
2407 png_ptr->unknown_chunk.size = (png_size_t)length;
2408 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002409 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002410 else
2411 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002412 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2413 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002414 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002415#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002416 if (png_ptr->read_user_chunk_fn != NULL)
2417 {
2418 /* Callback to user unknown chunk handler */
2419 int ret;
2420 ret = (*(png_ptr->read_user_chunk_fn))
2421 (png_ptr, &png_ptr->unknown_chunk);
2422 if (ret < 0)
2423 png_chunk_error(png_ptr, "error in user chunk");
2424 if (ret == 0)
2425 {
2426 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002427#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002428 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2429 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002430#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002431 png_chunk_error(png_ptr, "unknown critical chunk");
2432 png_set_unknown_chunks(png_ptr, info_ptr,
2433 &png_ptr->unknown_chunk, 1);
2434 }
2435 }
2436 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002437#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002438 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2439 png_free(png_ptr, png_ptr->unknown_chunk.data);
2440 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002441 }
2442 else
2443#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002444 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002445
2446 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002447
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002448#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002449 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002450#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002451}
2452
2453/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002454 * This function can't have the "critical chunk check" incorporated
2455 * into it, since in the future we will need to be able to call user
2456 * functions to handle unknown critical chunks after we check that
2457 * the chunk name itself is valid.
2458 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002459
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002460#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002461
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002462void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002463png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2464{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002465 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002466 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002467 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002468 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002469 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002470 }
2471}
2472
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002473/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002474 * row. This routine takes care of alpha and transparency if requested.
2475 * This routine also handles the two methods of progressive display
2476 * of interlaced images, depending on the mask value.
2477 * The mask value describes which pixels are to be combined with
2478 * the row. The pattern always repeats every 8 pixels, so just 8
2479 * bits are needed. A one indicates the pixel is to be combined,
2480 * a zero indicates the pixel is to be skipped. This is in addition
2481 * to any alpha or transparency value associated with the pixel. If
2482 * you want all pixels to be combined, pass 0xff (255) in mask.
2483 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002484
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002485void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002486png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002487{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002488 png_debug(1, "in png_combine_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002489 if (mask == 0xff)
2490 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002491 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002492 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002493 }
2494 else
2495 {
2496 switch (png_ptr->row_info.pixel_depth)
2497 {
2498 case 1:
2499 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002500 png_bytep sp = png_ptr->row_buf + 1;
2501 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002502 int s_inc, s_start, s_end;
2503 int m = 0x80;
2504 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002505 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002506 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002507
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002508#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002509 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002510 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002511 s_start = 0;
2512 s_end = 7;
2513 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002514 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002515 else
2516#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002517 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002518 s_start = 7;
2519 s_end = 0;
2520 s_inc = -1;
2521 }
2522
2523 shift = s_start;
2524
2525 for (i = 0; i < row_width; i++)
2526 {
2527 if (m & mask)
2528 {
2529 int value;
2530
2531 value = (*sp >> shift) & 0x01;
2532 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2533 *dp |= (png_byte)(value << shift);
2534 }
2535
2536 if (shift == s_end)
2537 {
2538 shift = s_start;
2539 sp++;
2540 dp++;
2541 }
2542 else
2543 shift += s_inc;
2544
2545 if (m == 1)
2546 m = 0x80;
2547 else
2548 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002549 }
2550 break;
2551 }
2552 case 2:
2553 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002554 png_bytep sp = png_ptr->row_buf + 1;
2555 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002556 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002557 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002558 int shift;
2559 png_uint_32 i;
2560 png_uint_32 row_width = png_ptr->width;
2561 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002562
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002563#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002564 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002565 {
2566 s_start = 0;
2567 s_end = 6;
2568 s_inc = 2;
2569 }
2570 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002571#endif
2572 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002573 s_start = 6;
2574 s_end = 0;
2575 s_inc = -2;
2576 }
2577
2578 shift = s_start;
2579
2580 for (i = 0; i < row_width; i++)
2581 {
2582 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002583 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002584 value = (*sp >> shift) & 0x03;
2585 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2586 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002587 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002588
2589 if (shift == s_end)
2590 {
2591 shift = s_start;
2592 sp++;
2593 dp++;
2594 }
2595 else
2596 shift += s_inc;
2597 if (m == 1)
2598 m = 0x80;
2599 else
2600 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002601 }
2602 break;
2603 }
2604 case 4:
2605 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002606 png_bytep sp = png_ptr->row_buf + 1;
2607 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002608 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002609 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002610 int shift;
2611 png_uint_32 i;
2612 png_uint_32 row_width = png_ptr->width;
2613 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002614
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002615#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002616 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002617 {
2618 s_start = 0;
2619 s_end = 4;
2620 s_inc = 4;
2621 }
2622 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002623#endif
2624 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002625 s_start = 4;
2626 s_end = 0;
2627 s_inc = -4;
2628 }
2629 shift = s_start;
2630
2631 for (i = 0; i < row_width; i++)
2632 {
2633 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002634 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002635 value = (*sp >> shift) & 0xf;
2636 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2637 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002638 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002639
2640 if (shift == s_end)
2641 {
2642 shift = s_start;
2643 sp++;
2644 dp++;
2645 }
2646 else
2647 shift += s_inc;
2648 if (m == 1)
2649 m = 0x80;
2650 else
2651 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002652 }
2653 break;
2654 }
2655 default:
2656 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002657 png_bytep sp = png_ptr->row_buf + 1;
2658 png_bytep dp = row;
2659 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2660 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002661 png_uint_32 row_width = png_ptr->width;
2662 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002663
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002664
2665 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002666 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002667 if (m & mask)
2668 {
2669 png_memcpy(dp, sp, pixel_bytes);
2670 }
2671
2672 sp += pixel_bytes;
2673 dp += pixel_bytes;
2674
2675 if (m == 1)
2676 m = 0x80;
2677 else
2678 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002679 }
2680 break;
2681 }
2682 }
2683 }
2684}
2685
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002686#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002687void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002688png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002689{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002690 png_row_infop row_info = &(png_ptr->row_info);
2691 png_bytep row = png_ptr->row_buf + 1;
2692 int pass = png_ptr->pass;
2693 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002694 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2695 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002696 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002697
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002698 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002699 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002700 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002701 png_uint_32 final_width;
2702
2703 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002704
2705 switch (row_info->pixel_depth)
2706 {
2707 case 1:
2708 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002709 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2710 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002711 int sshift, dshift;
2712 int s_start, s_end, s_inc;
2713 int jstop = png_pass_inc[pass];
2714 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002715 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002716 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002717
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002718#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002719 if (transformations & PNG_PACKSWAP)
2720 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002721 sshift = (int)((row_info->width + 7) & 0x07);
2722 dshift = (int)((final_width + 7) & 0x07);
2723 s_start = 7;
2724 s_end = 0;
2725 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002726 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002727 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002728#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002729 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002730 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2731 dshift = 7 - (int)((final_width + 7) & 0x07);
2732 s_start = 0;
2733 s_end = 7;
2734 s_inc = 1;
2735 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002736
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002737 for (i = 0; i < row_info->width; i++)
2738 {
2739 v = (png_byte)((*sp >> sshift) & 0x01);
2740 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002741 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002742 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2743 *dp |= (png_byte)(v << dshift);
2744 if (dshift == s_end)
2745 {
2746 dshift = s_start;
2747 dp--;
2748 }
2749 else
2750 dshift += s_inc;
2751 }
2752 if (sshift == s_end)
2753 {
2754 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002755 sp--;
2756 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002757 else
2758 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002759 }
2760 break;
2761 }
2762 case 2:
2763 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002764 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2765 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2766 int sshift, dshift;
2767 int s_start, s_end, s_inc;
2768 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002769 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002770
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002771#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002772 if (transformations & PNG_PACKSWAP)
2773 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002774 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2775 dshift = (int)(((final_width + 3) & 0x03) << 1);
2776 s_start = 6;
2777 s_end = 0;
2778 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002779 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002780 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002781#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002782 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002783 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2784 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2785 s_start = 0;
2786 s_end = 6;
2787 s_inc = 2;
2788 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002789
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002790 for (i = 0; i < row_info->width; i++)
2791 {
2792 png_byte v;
2793 int j;
2794
2795 v = (png_byte)((*sp >> sshift) & 0x03);
2796 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002797 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002798 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2799 *dp |= (png_byte)(v << dshift);
2800 if (dshift == s_end)
2801 {
2802 dshift = s_start;
2803 dp--;
2804 }
2805 else
2806 dshift += s_inc;
2807 }
2808 if (sshift == s_end)
2809 {
2810 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002811 sp--;
2812 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002813 else
2814 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002815 }
2816 break;
2817 }
2818 case 4:
2819 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002820 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2821 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002822 int sshift, dshift;
2823 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002824 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002825 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002826
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002827#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002828 if (transformations & PNG_PACKSWAP)
2829 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002830 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2831 dshift = (int)(((final_width + 1) & 0x01) << 2);
2832 s_start = 4;
2833 s_end = 0;
2834 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002835 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002836 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002837#endif
2838 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002839 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2840 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2841 s_start = 0;
2842 s_end = 4;
2843 s_inc = 4;
2844 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002845
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002846 for (i = 0; i < row_info->width; i++)
2847 {
2848 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2849 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002850
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002851 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002852 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002853 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2854 *dp |= (png_byte)(v << dshift);
2855 if (dshift == s_end)
2856 {
2857 dshift = s_start;
2858 dp--;
2859 }
2860 else
2861 dshift += s_inc;
2862 }
2863 if (sshift == s_end)
2864 {
2865 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002866 sp--;
2867 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002868 else
2869 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 }
2871 break;
2872 }
2873 default:
2874 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002875 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002876 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2877 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002878 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002879
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002880 int jstop = png_pass_inc[pass];
2881 png_uint_32 i;
2882
2883 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002884 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002885 png_byte v[8];
2886 int j;
2887
2888 png_memcpy(v, sp, pixel_bytes);
2889 for (j = 0; j < jstop; j++)
2890 {
2891 png_memcpy(dp, v, pixel_bytes);
2892 dp -= pixel_bytes;
2893 }
2894 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002895 }
2896 break;
2897 }
2898 }
2899 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002900 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002901 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002902#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002903 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002904#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002905}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002906#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002907
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002908void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002909png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002910 png_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002911{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002912 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06002913 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002914 switch (filter)
2915 {
2916 case PNG_FILTER_VALUE_NONE:
2917 break;
2918 case PNG_FILTER_VALUE_SUB:
2919 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002920 png_uint_32 i;
2921 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002922 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002923 png_bytep rp = row + bpp;
2924 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002925
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002926 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002927 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002928 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2929 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002930 }
2931 break;
2932 }
2933 case PNG_FILTER_VALUE_UP:
2934 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002935 png_uint_32 i;
2936 png_uint_32 istop = row_info->rowbytes;
2937 png_bytep rp = row;
2938 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002939
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002940 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002941 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002942 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2943 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002944 }
2945 break;
2946 }
2947 case PNG_FILTER_VALUE_AVG:
2948 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002949 png_uint_32 i;
2950 png_bytep rp = row;
2951 png_bytep pp = prev_row;
2952 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002953 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002954 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002955
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002956 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002957 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002958 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002959 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002960 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002961 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002962
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002963 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002964 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002965 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002966 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002967 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002968 }
2969 break;
2970 }
2971 case PNG_FILTER_VALUE_PAETH:
2972 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002973 png_uint_32 i;
2974 png_bytep rp = row;
2975 png_bytep pp = prev_row;
2976 png_bytep lp = row;
2977 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002978 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002979 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002980
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002981 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002982 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002983 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2984 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002985 }
2986
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002987 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002988 {
2989 int a, b, c, pa, pb, pc, p;
2990
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002991 a = *lp++;
2992 b = *pp++;
2993 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002994
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002995 p = b - c;
2996 pc = a - c;
2997
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002998#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002999 pa = abs(p);
3000 pb = abs(pc);
3001 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003002#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003003 pa = p < 0 ? -p : p;
3004 pb = pc < 0 ? -pc : pc;
3005 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003006#endif
3007
3008 /*
3009 if (pa <= pb && pa <= pc)
3010 p = a;
3011 else if (pb <= pc)
3012 p = b;
3013 else
3014 p = c;
3015 */
3016
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003017 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003018
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003019 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3020 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003021 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003022 break;
3023 }
3024 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003025 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003026 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003027 break;
3028 }
3029}
Guy Schalnat0d580581995-07-20 02:43:20 -05003030
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003031#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003032void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003033png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003034{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003035#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003036 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003037
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003038 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003039 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003040
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003041 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003042 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003043
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003044 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003045 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003046
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003047 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003048 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3049#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003050
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003051 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003052 png_ptr->row_number++;
3053 if (png_ptr->row_number < png_ptr->num_rows)
3054 return;
3055
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003056#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003057 if (png_ptr->interlaced)
3058 {
3059 png_ptr->row_number = 0;
Glenn Randers-Pehrsona31c74f2009-05-18 15:52:01 -05003060 png_memset(png_ptr->prev_row, 0,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003061 png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003062 do
3063 {
3064 png_ptr->pass++;
3065 if (png_ptr->pass >= 7)
3066 break;
3067 png_ptr->iwidth = (png_ptr->width +
3068 png_pass_inc[png_ptr->pass] - 1 -
3069 png_pass_start[png_ptr->pass]) /
3070 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003071
Guy Schalnat0d580581995-07-20 02:43:20 -05003072 if (!(png_ptr->transformations & PNG_INTERLACE))
3073 {
3074 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003075 png_pass_yinc[png_ptr->pass] - 1 -
3076 png_pass_ystart[png_ptr->pass]) /
3077 png_pass_yinc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003078 if (!(png_ptr->num_rows))
3079 continue;
3080 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003081 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003082 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003083 } while (png_ptr->iwidth == 0);
3084
3085 if (png_ptr->pass < 7)
3086 return;
3087 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003088#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003089
Guy Schalnate5a37791996-06-05 15:50:50 -05003090 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003091 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003092 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003093 char extra;
3094 int ret;
3095
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003096 png_ptr->zstream.next_out = (Byte *)&extra;
3097 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003098 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003099 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003100 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003101 {
3102 while (!png_ptr->idat_size)
3103 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003104 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003105
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003106 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003107
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003108 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003109 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003111 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003112 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003113 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003114
3115 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003116 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3117 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05003118 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003119 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3120 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3121 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003122 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003123 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05003124 if (ret == Z_STREAM_END)
3125 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003126 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003127 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003128 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003129 png_ptr->mode |= PNG_AFTER_IDAT;
3130 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003131 break;
3132 }
3133 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003134 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003135 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003136
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003137 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003138 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003139 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003140 png_ptr->mode |= PNG_AFTER_IDAT;
3141 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3142 break;
3143 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003144
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003145 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003146 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003147 }
3148
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003149 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003150 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003151
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003152 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003153
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003154 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003155}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003156#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003157
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003158void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003159png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003160{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003161#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003162 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003163
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003164 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003165 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003166
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003167 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003168 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003169
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003170 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003171 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003172
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003173 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003174 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3175#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003176
Guy Schalnat0d580581995-07-20 02:43:20 -05003177 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003178 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003179
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003180 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003181 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003182 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003183#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003184 if (png_ptr->interlaced)
3185 {
3186 if (!(png_ptr->transformations & PNG_INTERLACE))
3187 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003188 png_pass_ystart[0]) / png_pass_yinc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05003189 else
3190 png_ptr->num_rows = png_ptr->height;
3191
3192 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003193 png_pass_inc[png_ptr->pass] - 1 -
3194 png_pass_start[png_ptr->pass]) /
3195 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003196 }
3197 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003198#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003199 {
3200 png_ptr->num_rows = png_ptr->height;
3201 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003202 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003203 max_pixel_depth = png_ptr->pixel_depth;
3204
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003205#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003206 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003207 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003208#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003209
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003210#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003211 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003212 {
3213 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3214 {
3215 if (png_ptr->num_trans)
3216 max_pixel_depth = 32;
3217 else
3218 max_pixel_depth = 24;
3219 }
3220 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3221 {
3222 if (max_pixel_depth < 8)
3223 max_pixel_depth = 8;
3224 if (png_ptr->num_trans)
3225 max_pixel_depth *= 2;
3226 }
3227 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3228 {
3229 if (png_ptr->num_trans)
3230 {
3231 max_pixel_depth *= 4;
3232 max_pixel_depth /= 3;
3233 }
3234 }
3235 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003236#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003237
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003238#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003239 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003240 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003241 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3242 max_pixel_depth = 32;
3243 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003244 {
3245 if (max_pixel_depth <= 8)
3246 max_pixel_depth = 16;
3247 else
3248 max_pixel_depth = 32;
3249 }
3250 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3251 {
3252 if (max_pixel_depth <= 32)
3253 max_pixel_depth = 32;
3254 else
3255 max_pixel_depth = 64;
3256 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003257 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003258#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003259
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003260#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003261 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3262 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003263 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003264#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003265 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003266#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003267#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003268 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003269#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003270 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003271 {
3272 if (max_pixel_depth <= 16)
3273 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003274 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003275 max_pixel_depth = 64;
3276 }
3277 else
3278 {
3279 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003280 {
3281 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003282 max_pixel_depth = 32;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003283 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003284 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003285 }
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003286 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3287 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003288 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003289 max_pixel_depth = 48;
3290 }
3291 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003292#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003293
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003294#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3295defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003296 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003297 {
3298 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003299 png_ptr->user_transform_channels;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003300 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003301 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003302 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003303#endif
3304
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003305 /* Align the width on the next larger 8 pixels. Mainly used
3306 * for interlacing
3307 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003308 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003309 /* Calculate the maximum bytes needed, adding a byte and a pixel
3310 * for safety's sake
3311 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003312 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003313 1 + ((max_pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003314#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003315 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003316 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003317#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003318
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003319 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003320 {
3321 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003322 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003323 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3324 row_bytes + 48);
3325 else
3326 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3327 row_bytes + 48);
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003328 png_ptr->old_big_row_buf_size = row_bytes + 48;
3329
3330#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3331 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3332 * of padding before and after row_buf.
3333 */
3334 png_ptr->row_buf = png_ptr->big_row_buf + 32
3335 - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16);
3336 png_ptr->old_big_row_buf_size = row_bytes + 48;
3337#else
3338 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003339 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003340#endif
3341 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003342 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003343
3344#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003345 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003346 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003347#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003348 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003349 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003350
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003351 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003352 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003353 png_free(png_ptr, png_ptr->prev_row);
3354 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003355 png_ptr->rowbytes + 1));
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003356 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003357 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003358
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003359 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003360
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003361 png_debug1(3, "width = %u,", png_ptr->width);
3362 png_debug1(3, "height = %u,", png_ptr->height);
3363 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3364 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3365 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3366 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003367 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003368
Guy Schalnate5a37791996-06-05 15:50:50 -05003369 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003370}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003371#endif /* PNG_READ_SUPPORTED */