blob: 26a2c1e358e5a3d853685beddb85885264873fbc [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-Pehrsond7da8bb2010-03-13 20:30:10 -06004 * Last changed in libpng 1.4.1 [March 14, 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-Pehrson9c3ab682006-02-20 22:09:05 -060032png_uint_32 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060033png_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-Pehrson9c3ab682006-02-20 22:09:05 -060048png_int_32 PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -050049png_get_int_32(png_bytep buf)
50{
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-Pehrson9c3ab682006-02-20 22:09:05 -060060png_uint_16 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060061png_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-Pehrson72cda2d2010-03-06 08:18:03 -0600907 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500908 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600909 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600910#endif
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500911#endif /* PNG_CONSOLE_IO_SUPPORTED */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600912 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600913 return;
914 }
915#endif /* PNG_READ_sRGB_SUPPORTED */
916
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600917#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500918 png_set_cHRM(png_ptr, info_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600919 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600920#endif
921#ifdef PNG_FIXED_POINT_SUPPORTED
922 png_set_cHRM_fixed(png_ptr, info_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600923 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
924 int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600925#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500926}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500927#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500928
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500929#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500930void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600931png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
932{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600933 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600934 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600935
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500936 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600937
938 if (!(png_ptr->mode & PNG_HAVE_IHDR))
939 png_error(png_ptr, "Missing IHDR before sRGB");
940 else if (png_ptr->mode & PNG_HAVE_IDAT)
941 {
942 png_warning(png_ptr, "Invalid sRGB after IDAT");
943 png_crc_finish(png_ptr, length);
944 return;
945 }
946 else if (png_ptr->mode & PNG_HAVE_PLTE)
947 /* Should be an error, but we can cope with it */
948 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600949
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500950 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600951 {
952 png_warning(png_ptr, "Duplicate sRGB chunk");
953 png_crc_finish(png_ptr, length);
954 return;
955 }
956
957 if (length != 1)
958 {
959 png_warning(png_ptr, "Incorrect sRGB chunk length");
960 png_crc_finish(png_ptr, length);
961 return;
962 }
963
964 png_crc_read(png_ptr, buf, 1);
965 if (png_crc_finish(png_ptr, 0))
966 return;
967
968 intent = buf[0];
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500969 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600970 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600971 {
972 png_warning(png_ptr, "Unknown sRGB intent");
973 return;
974 }
975
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600976#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600977 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600978 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500979 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600980#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500981 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600982#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600983# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500984 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600985# endif
986#endif
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500987 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600988 {
989 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600990 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500991#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600992# ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500993 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600994 (int)png_ptr->int_gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600995# else
996# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500997 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600998# endif
999# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001000#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001001 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001002 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001003#endif /* PNG_READ_gAMA_SUPPORTED */
1004
1005#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001006#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001007 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -05001008 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
1009 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
1010 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
1011 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
1012 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
1013 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
1014 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
1015 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001016 {
1017 png_warning(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001018 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001019 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001020#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001021#endif /* PNG_READ_cHRM_SUPPORTED */
1022
1023 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1024}
1025#endif /* PNG_READ_sRGB_SUPPORTED */
1026
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001027#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001028void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001029png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1030/* Note: this does not properly handle chunks that are > 64K under DOS */
1031{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001032 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001033 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001034 png_charp profile;
1035 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001036 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001037 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001038
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001039 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001040
1041 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1042 png_error(png_ptr, "Missing IHDR before iCCP");
1043 else if (png_ptr->mode & PNG_HAVE_IDAT)
1044 {
1045 png_warning(png_ptr, "Invalid iCCP after IDAT");
1046 png_crc_finish(png_ptr, length);
1047 return;
1048 }
1049 else if (png_ptr->mode & PNG_HAVE_PLTE)
1050 /* Should be an error, but we can cope with it */
1051 png_warning(png_ptr, "Out of place iCCP chunk");
1052
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001053 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001054 {
1055 png_warning(png_ptr, "Duplicate iCCP chunk");
1056 png_crc_finish(png_ptr, length);
1057 return;
1058 }
1059
1060#ifdef PNG_MAX_MALLOC_64K
1061 if (length > (png_uint_32)65535L)
1062 {
1063 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1064 skip = length - (png_uint_32)65535L;
1065 length = (png_uint_32)65535L;
1066 }
1067#endif
1068
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001069 png_free(png_ptr, png_ptr->chunkdata);
1070 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001071 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001072 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001073
1074 if (png_crc_finish(png_ptr, skip))
1075 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001076 png_free(png_ptr, png_ptr->chunkdata);
1077 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001078 return;
1079 }
1080
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001081 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001082
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001083 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001084 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001085
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001086 ++profile;
1087
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001088 /* There should be at least one zero (the compression type byte)
1089 * following the separator, and we should be on it
1090 */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001091 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001092 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001093 png_free(png_ptr, png_ptr->chunkdata);
1094 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001095 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001096 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001097 }
1098
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001099 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001100 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001101 if (compression_type)
1102 {
1103 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001104 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001105 wrote nonzero) */
1106 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001107
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001108 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001109 png_decompress_chunk(png_ptr, compression_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001110 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001111
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001112 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001113
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001114 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001115 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001116 png_free(png_ptr, png_ptr->chunkdata);
1117 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001118 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1119 return;
1120 }
1121
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001122 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001123 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001124 profile_size = ((*(pC )) << 24) |
1125 ((*(pC + 1)) << 16) |
1126 ((*(pC + 2)) << 8) |
1127 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001128
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001129 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001130 profile_length = profile_size;
1131
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001132 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001133 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001134 png_free(png_ptr, png_ptr->chunkdata);
1135 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001136 png_warning(png_ptr, "Ignoring truncated iCCP profile");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001137#ifdef PNG_STDIO_SUPPORTED
1138 {
1139 char umsg[50];
1140
1141 png_snprintf(umsg, 50, "declared profile size = %lu",
1142 (unsigned long)profile_size);
1143 png_warning(png_ptr, umsg);
1144 png_snprintf(umsg, 50, "actual profile length = %lu",
1145 (unsigned long)profile_length);
1146 png_warning(png_ptr, umsg);
1147 }
1148#endif
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001149 return;
1150 }
1151
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001152 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001153 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001154 png_free(png_ptr, png_ptr->chunkdata);
1155 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001156}
1157#endif /* PNG_READ_iCCP_SUPPORTED */
1158
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001159#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001160void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001161png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1162/* Note: this does not properly handle chunks that are > 64K under DOS */
1163{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001164 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001165 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001166#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001167 png_sPLT_entryp pp;
1168#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001169 int data_length, entry_size, i;
1170 png_uint_32 skip = 0;
1171 png_size_t slength;
1172
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001173 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001174
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001175#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001176
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001177 if (png_ptr->user_chunk_cache_max != 0)
1178 {
1179 if (png_ptr->user_chunk_cache_max == 1)
1180 {
1181 png_crc_finish(png_ptr, length);
1182 return;
1183 }
1184 if (--png_ptr->user_chunk_cache_max == 1)
1185 {
1186 png_warning(png_ptr, "No space in chunk cache for sPLT");
1187 png_crc_finish(png_ptr, length);
1188 return;
1189 }
1190 }
1191#endif
1192
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001193 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1194 png_error(png_ptr, "Missing IHDR before sPLT");
1195 else if (png_ptr->mode & PNG_HAVE_IDAT)
1196 {
1197 png_warning(png_ptr, "Invalid sPLT after IDAT");
1198 png_crc_finish(png_ptr, length);
1199 return;
1200 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001201
1202#ifdef PNG_MAX_MALLOC_64K
1203 if (length > (png_uint_32)65535L)
1204 {
1205 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1206 skip = length - (png_uint_32)65535L;
1207 length = (png_uint_32)65535L;
1208 }
1209#endif
1210
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001211 png_free(png_ptr, png_ptr->chunkdata);
1212 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001213 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001214 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001215
1216 if (png_crc_finish(png_ptr, skip))
1217 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001218 png_free(png_ptr, png_ptr->chunkdata);
1219 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001220 return;
1221 }
1222
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001223 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001224
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001225 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1226 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001227 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001228 ++entry_start;
1229
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001230 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001231 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001232 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001233 png_free(png_ptr, png_ptr->chunkdata);
1234 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001235 png_warning(png_ptr, "malformed sPLT chunk");
1236 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001237 }
1238
1239 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001240 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001241 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001242
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001243 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001244 if (data_length % entry_size)
1245 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001246 png_free(png_ptr, png_ptr->chunkdata);
1247 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001248 png_warning(png_ptr, "sPLT chunk has bad length");
1249 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001250 }
1251
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001252 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001253 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001254 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001255 {
1256 png_warning(png_ptr, "sPLT chunk too long");
1257 return;
1258 }
1259 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001260 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001261 if (new_palette.entries == NULL)
1262 {
1263 png_warning(png_ptr, "sPLT chunk requires too much memory");
1264 return;
1265 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001266
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001267#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001268 for (i = 0; i < new_palette.nentries; i++)
1269 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001270 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001271
1272 if (new_palette.depth == 8)
1273 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001274 pp->red = *entry_start++;
1275 pp->green = *entry_start++;
1276 pp->blue = *entry_start++;
1277 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001278 }
1279 else
1280 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001281 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1282 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1283 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1284 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001285 }
1286 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1287 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001288#else
1289 pp = new_palette.entries;
1290 for (i = 0; i < new_palette.nentries; i++)
1291 {
1292
1293 if (new_palette.depth == 8)
1294 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001295 pp[i].red = *entry_start++;
1296 pp[i].green = *entry_start++;
1297 pp[i].blue = *entry_start++;
1298 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001299 }
1300 else
1301 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001302 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1303 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1304 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1305 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001306 }
1307 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1308 }
1309#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001310
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001311 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001312 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001313
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001314 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001315
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001316 png_free(png_ptr, png_ptr->chunkdata);
1317 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001318 png_free(png_ptr, new_palette.entries);
1319}
1320#endif /* PNG_READ_sPLT_SUPPORTED */
1321
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001322#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001323void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001324png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001325{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001326 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001327
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001328 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001329
Guy Schalnate5a37791996-06-05 15:50:50 -05001330 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1331 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001332 else if (png_ptr->mode & PNG_HAVE_IDAT)
1333 {
1334 png_warning(png_ptr, "Invalid tRNS after IDAT");
1335 png_crc_finish(png_ptr, length);
1336 return;
1337 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001338 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001339 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001340 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001341 png_crc_finish(png_ptr, length);
1342 return;
1343 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001344
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001345 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001346 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001347 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001348
1349 if (length != 2)
1350 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001351 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001352 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001353 return;
1354 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001355
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001356 png_crc_read(png_ptr, buf, 2);
1357 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001358 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001359 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001360 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1361 {
1362 png_byte buf[6];
1363
1364 if (length != 6)
1365 {
1366 png_warning(png_ptr, "Incorrect tRNS chunk length");
1367 png_crc_finish(png_ptr, length);
1368 return;
1369 }
1370 png_crc_read(png_ptr, buf, (png_size_t)length);
1371 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001372 png_ptr->trans_color.red = png_get_uint_16(buf);
1373 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1374 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001375 }
1376 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1377 {
1378 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1379 {
1380 /* Should be an error, but we can cope with it. */
1381 png_warning(png_ptr, "Missing PLTE before tRNS");
1382 }
1383 if (length > (png_uint_32)png_ptr->num_palette ||
1384 length > PNG_MAX_PALETTE_LENGTH)
1385 {
1386 png_warning(png_ptr, "Incorrect tRNS chunk length");
1387 png_crc_finish(png_ptr, length);
1388 return;
1389 }
1390 if (length == 0)
1391 {
1392 png_warning(png_ptr, "Zero length tRNS chunk");
1393 png_crc_finish(png_ptr, length);
1394 return;
1395 }
1396 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1397 png_ptr->num_trans = (png_uint_16)length;
1398 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001399 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001400 {
1401 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001402 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001403 return;
1404 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001405
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001406 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001407 {
1408 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001409 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001410 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001411
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001412 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001413 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001414}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001415#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001416
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001417#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001418void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001419png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001420{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001421 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001422 png_byte buf[6];
1423
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001424 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001425
Guy Schalnate5a37791996-06-05 15:50:50 -05001426 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1427 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001428 else if (png_ptr->mode & PNG_HAVE_IDAT)
1429 {
1430 png_warning(png_ptr, "Invalid bKGD after IDAT");
1431 png_crc_finish(png_ptr, length);
1432 return;
1433 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001434 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001435 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001436 {
1437 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001438 png_crc_finish(png_ptr, length);
1439 return;
1440 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001441 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001442 {
1443 png_warning(png_ptr, "Duplicate bKGD chunk");
1444 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001445 return;
1446 }
1447
Guy Schalnat0d580581995-07-20 02:43:20 -05001448 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1449 truelen = 1;
1450 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1451 truelen = 6;
1452 else
1453 truelen = 2;
1454
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001455 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001456 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001457 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001458 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001459 return;
1460 }
1461
Andreas Dilger47a0c421997-05-16 02:46:07 -05001462 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001463 if (png_crc_finish(png_ptr, 0))
1464 return;
1465
Guy Schalnate5a37791996-06-05 15:50:50 -05001466 /* We convert the index value into RGB components so that we can allow
1467 * arbitrary RGB values for background when we have transparency, and
1468 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001469 * from the info_ptr struct.
1470 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001471 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001472 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001473 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001474 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001475 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001476 if (buf[0] >= info_ptr->num_palette)
1477 {
1478 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1479 return;
1480 }
1481 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001482 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001483 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001484 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001485 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001486 (png_uint_16)png_ptr->palette[buf[0]].blue;
1487 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001488 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001489 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001490 {
1491 png_ptr->background.red =
1492 png_ptr->background.green =
1493 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001494 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001495 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001496 else
1497 {
1498 png_ptr->background.red = png_get_uint_16(buf);
1499 png_ptr->background.green = png_get_uint_16(buf + 2);
1500 png_ptr->background.blue = png_get_uint_16(buf + 4);
1501 }
1502
Andreas Dilger47a0c421997-05-16 02:46:07 -05001503 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001504}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001505#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001506
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001507#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001508void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001509png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001510{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001511 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001512 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001513
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001514 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001515
Guy Schalnate5a37791996-06-05 15:50:50 -05001516 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1517 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001518 else if (png_ptr->mode & PNG_HAVE_IDAT)
1519 {
1520 png_warning(png_ptr, "Invalid hIST after IDAT");
1521 png_crc_finish(png_ptr, length);
1522 return;
1523 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001524 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1525 {
1526 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001527 png_crc_finish(png_ptr, length);
1528 return;
1529 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001530 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001531 {
1532 png_warning(png_ptr, "Duplicate hIST chunk");
1533 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001534 return;
1535 }
1536
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001537 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001538 if (num != (unsigned int) png_ptr->num_palette || num >
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001539 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001540 {
1541 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001542 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001543 return;
1544 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001545
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001546 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001547 {
1548 png_byte buf[2];
1549
1550 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001551 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001552 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001553
1554 if (png_crc_finish(png_ptr, 0))
1555 return;
1556
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001557 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001558}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001559#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001560
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001561#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001562void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001563png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001564{
1565 png_byte buf[9];
1566 png_uint_32 res_x, res_y;
1567 int unit_type;
1568
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001569 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001570
Guy Schalnate5a37791996-06-05 15:50:50 -05001571 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001572 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001573 else if (png_ptr->mode & PNG_HAVE_IDAT)
1574 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001575 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001576 png_crc_finish(png_ptr, length);
1577 return;
1578 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001579 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001580 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001581 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001582 png_crc_finish(png_ptr, length);
1583 return;
1584 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001585
Guy Schalnat0d580581995-07-20 02:43:20 -05001586 if (length != 9)
1587 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001588 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001589 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001590 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001591 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001592
1593 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001594 if (png_crc_finish(png_ptr, 0))
1595 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001596
1597 res_x = png_get_uint_32(buf);
1598 res_y = png_get_uint_32(buf + 4);
1599 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001600 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001601}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001602#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001603
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001604#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001605void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001606png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001607{
1608 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001609 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001610 int unit_type;
1611
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001612 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001613
Guy Schalnate5a37791996-06-05 15:50:50 -05001614 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1615 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001616 else if (png_ptr->mode & PNG_HAVE_IDAT)
1617 {
1618 png_warning(png_ptr, "Invalid oFFs after IDAT");
1619 png_crc_finish(png_ptr, length);
1620 return;
1621 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001622 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001623 {
1624 png_warning(png_ptr, "Duplicate oFFs chunk");
1625 png_crc_finish(png_ptr, length);
1626 return;
1627 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001628
Guy Schalnat0d580581995-07-20 02:43:20 -05001629 if (length != 9)
1630 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001631 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001632 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001633 return;
1634 }
1635
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001636 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001637 if (png_crc_finish(png_ptr, 0))
1638 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001639
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001640 offset_x = png_get_int_32(buf);
1641 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001642 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1644}
1645#endif
1646
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001647#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001648/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001649void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001650png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1651{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001652 png_int_32 X0, X1;
1653 png_byte type, nparams;
1654 png_charp buf, units, endptr;
1655 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001656 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001657 int i;
1658
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001659 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001660
1661 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1662 png_error(png_ptr, "Missing IHDR before pCAL");
1663 else if (png_ptr->mode & PNG_HAVE_IDAT)
1664 {
1665 png_warning(png_ptr, "Invalid pCAL after IDAT");
1666 png_crc_finish(png_ptr, length);
1667 return;
1668 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001669 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001670 {
1671 png_warning(png_ptr, "Duplicate pCAL chunk");
1672 png_crc_finish(png_ptr, length);
1673 return;
1674 }
1675
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001676 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001677 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001678 png_free(png_ptr, png_ptr->chunkdata);
1679 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1680 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001681 {
1682 png_warning(png_ptr, "No memory for pCAL purpose");
1683 return;
1684 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001685 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001686 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001687
1688 if (png_crc_finish(png_ptr, 0))
1689 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001690 png_free(png_ptr, png_ptr->chunkdata);
1691 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001692 return;
1693 }
1694
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001695 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001696
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001697 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001698 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001699 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001700
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001701 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001702
1703 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001704 * in order to get the parameter information.
1705 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001706 if (endptr <= buf + 12)
1707 {
1708 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001709 png_free(png_ptr, png_ptr->chunkdata);
1710 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001711 return;
1712 }
1713
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001714 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001715 X0 = png_get_int_32((png_bytep)buf+1);
1716 X1 = png_get_int_32((png_bytep)buf+5);
1717 type = buf[9];
1718 nparams = buf[10];
1719 units = buf + 11;
1720
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001721 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001722 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001723 * equation types.
1724 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001725 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1726 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1727 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1728 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1729 {
1730 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001731 png_free(png_ptr, png_ptr->chunkdata);
1732 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001733 return;
1734 }
1735 else if (type >= PNG_EQUATION_LAST)
1736 {
1737 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1738 }
1739
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001740 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001741 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001742
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001743 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001744 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001745 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001746 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001747 {
1748 png_free(png_ptr, png_ptr->chunkdata);
1749 png_ptr->chunkdata = NULL;
1750 png_warning(png_ptr, "No memory for pCAL params");
1751 return;
1752 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001753
1754 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001755 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001756 {
1757 buf++; /* Skip the null string terminator from previous parameter. */
1758
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001759 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001760 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001761 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001762
1763 /* Make sure we haven't run out of data yet */
1764 if (buf > endptr)
1765 {
1766 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001767 png_free(png_ptr, png_ptr->chunkdata);
1768 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001769 png_free(png_ptr, params);
1770 return;
1771 }
1772 }
1773
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001774 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001775 units, params);
1776
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001777 png_free(png_ptr, png_ptr->chunkdata);
1778 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001779 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001780}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001781#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001782
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001783#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001784/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001785void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001786png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1787{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001788 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001789#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001790 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001791 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001792#else
1793#ifdef PNG_FIXED_POINT_SUPPORTED
1794 png_charp swidth, sheight;
1795#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001796#endif
1797 png_size_t slength;
1798
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001799 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001800
1801 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1802 png_error(png_ptr, "Missing IHDR before sCAL");
1803 else if (png_ptr->mode & PNG_HAVE_IDAT)
1804 {
1805 png_warning(png_ptr, "Invalid sCAL after IDAT");
1806 png_crc_finish(png_ptr, length);
1807 return;
1808 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001809 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001810 {
1811 png_warning(png_ptr, "Duplicate sCAL chunk");
1812 png_crc_finish(png_ptr, length);
1813 return;
1814 }
1815
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001816 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001817 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001818 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1819 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001820 {
1821 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1822 return;
1823 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001824 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001825 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001826
1827 if (png_crc_finish(png_ptr, 0))
1828 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001829 png_free(png_ptr, png_ptr->chunkdata);
1830 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001831 return;
1832 }
1833
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001834 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001835
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001836 ep = png_ptr->chunkdata + 1; /* Skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001837
1838#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001839 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001840 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001841 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001842 png_warning(png_ptr, "malformed width string in sCAL chunk");
1843 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001844 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001845#else
1846#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001847 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1848 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001849 {
1850 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1851 return;
1852 }
1853 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001854#endif
1855#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001856
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001857 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001858 /* Empty loop */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001859 ep++;
1860
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001861 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001862 {
1863 png_warning(png_ptr, "Truncated sCAL chunk");
1864#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1865 !defined(PNG_FLOATING_POINT_SUPPORTED)
1866 png_free(png_ptr, swidth);
1867#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001868 png_free(png_ptr, png_ptr->chunkdata);
1869 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001870 return;
1871 }
1872
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001873#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001874 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001875 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001876 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001877 png_warning(png_ptr, "malformed height string in sCAL chunk");
1878 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001879 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001880#else
1881#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001882 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001883 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001884 {
1885 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1886 return;
1887 }
1888 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001889#endif
1890#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001891
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001892 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001893#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001894 || width <= 0. || height <= 0.
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001895#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001896 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001897 {
1898 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001899 png_free(png_ptr, png_ptr->chunkdata);
1900 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001901#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001902 png_free(png_ptr, swidth);
1903 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001904#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001905 return;
1906 }
1907
1908
1909#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001910 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001911#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001912#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001913 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001914#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001915#endif
1916
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001917 png_free(png_ptr, png_ptr->chunkdata);
1918 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001919#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1920 png_free(png_ptr, swidth);
1921 png_free(png_ptr, sheight);
1922#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001923}
1924#endif
1925
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001926#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001927void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001928png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001929{
1930 png_byte buf[7];
1931 png_time mod_time;
1932
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001933 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001934
Guy Schalnate5a37791996-06-05 15:50:50 -05001935 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001936 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001937 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001938 {
1939 png_warning(png_ptr, "Duplicate tIME chunk");
1940 png_crc_finish(png_ptr, length);
1941 return;
1942 }
1943
1944 if (png_ptr->mode & PNG_HAVE_IDAT)
1945 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001946
Guy Schalnat0d580581995-07-20 02:43:20 -05001947 if (length != 7)
1948 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001949 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001950 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001951 return;
1952 }
1953
1954 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001955 if (png_crc_finish(png_ptr, 0))
1956 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001957
1958 mod_time.second = buf[6];
1959 mod_time.minute = buf[5];
1960 mod_time.hour = buf[4];
1961 mod_time.day = buf[3];
1962 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001963 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001964
Andreas Dilger47a0c421997-05-16 02:46:07 -05001965 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001966}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001967#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001968
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001969#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001970/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001971void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001972png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001973{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001974 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001975 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001976 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001977 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001978 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001979 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001980
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001981 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05001982
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001983#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001984 if (png_ptr->user_chunk_cache_max != 0)
1985 {
1986 if (png_ptr->user_chunk_cache_max == 1)
1987 {
1988 png_crc_finish(png_ptr, length);
1989 return;
1990 }
1991 if (--png_ptr->user_chunk_cache_max == 1)
1992 {
1993 png_warning(png_ptr, "No space in chunk cache for tEXt");
1994 png_crc_finish(png_ptr, length);
1995 return;
1996 }
1997 }
1998#endif
1999
Guy Schalnate5a37791996-06-05 15:50:50 -05002000 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2001 png_error(png_ptr, "Missing IHDR before tEXt");
2002
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002003 if (png_ptr->mode & PNG_HAVE_IDAT)
2004 png_ptr->mode |= PNG_AFTER_IDAT;
2005
Andreas Dilger47a0c421997-05-16 02:46:07 -05002006#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002007 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002008 {
2009 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002010 skip = length - (png_uint_32)65535L;
2011 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002012 }
2013#endif
2014
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002015 png_free(png_ptr, png_ptr->chunkdata);
2016
2017 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2018 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002019 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002020 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002021 return;
2022 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002023 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002024 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002025
2026 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002027 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002028 png_free(png_ptr, png_ptr->chunkdata);
2029 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002030 return;
2031 }
2032
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002033 key = png_ptr->chunkdata;
2034
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002035 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002036
2037 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002038 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002039
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002040 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002041 text++;
2042
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002043 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002044 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002045 if (text_ptr == NULL)
2046 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002047 png_warning(png_ptr, "Not enough memory to process text chunk");
2048 png_free(png_ptr, png_ptr->chunkdata);
2049 png_ptr->chunkdata = NULL;
2050 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002051 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002052 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2053 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002054#ifdef PNG_iTXt_SUPPORTED
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;
2058#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002059 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002060 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002061
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002062 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002063
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002064 png_free(png_ptr, png_ptr->chunkdata);
2065 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002066 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002067 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002068 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002069}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002070#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002071
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002072#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002073/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002074void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002075png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002076{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002077 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002078 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002079 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002080 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002081 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002082
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002083 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002084
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002085#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002086 if (png_ptr->user_chunk_cache_max != 0)
2087 {
2088 if (png_ptr->user_chunk_cache_max == 1)
2089 {
2090 png_crc_finish(png_ptr, length);
2091 return;
2092 }
2093 if (--png_ptr->user_chunk_cache_max == 1)
2094 {
2095 png_warning(png_ptr, "No space in chunk cache for zTXt");
2096 png_crc_finish(png_ptr, length);
2097 return;
2098 }
2099 }
2100#endif
2101
Guy Schalnate5a37791996-06-05 15:50:50 -05002102 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2103 png_error(png_ptr, "Missing IHDR before zTXt");
2104
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002105 if (png_ptr->mode & PNG_HAVE_IDAT)
2106 png_ptr->mode |= PNG_AFTER_IDAT;
2107
Andreas Dilger47a0c421997-05-16 02:46:07 -05002108#ifdef PNG_MAX_MALLOC_64K
2109 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002110 * there is no hard and fast rule to tell us where to stop.
2111 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002112 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002113 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002114 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2115 png_crc_finish(png_ptr, length);
2116 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002117 }
2118#endif
2119
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002120 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002121 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2122 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002123 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002124 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2125 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002126 }
2127 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002128 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002129 if (png_crc_finish(png_ptr, 0))
2130 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002131 png_free(png_ptr, png_ptr->chunkdata);
2132 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002133 return;
2134 }
2135
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002136 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002137
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002138 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002139 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002140
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002141 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002142 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002143 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002144 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002145 png_free(png_ptr, png_ptr->chunkdata);
2146 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002147 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002148 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002149 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002150 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002151 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002152 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2153 {
2154 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2155 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2156 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002157 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002158 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002159 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002160
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002161 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002162 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002163
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002164 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002165 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002166 if (text_ptr == NULL)
2167 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002168 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2169 png_free(png_ptr, png_ptr->chunkdata);
2170 png_ptr->chunkdata = NULL;
2171 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002172 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002173 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002174 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002175#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002176 text_ptr->lang = NULL;
2177 text_ptr->lang_key = NULL;
2178 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002179#endif
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002180 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002181 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002182
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002183 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002184
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002185 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002186 png_free(png_ptr, png_ptr->chunkdata);
2187 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002188 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002189 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002190}
2191#endif
2192
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002193#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002194/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002195void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002196png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2197{
2198 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002199 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002200 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002201 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002202 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002203 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002204
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002205 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002206
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002207#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002208 if (png_ptr->user_chunk_cache_max != 0)
2209 {
2210 if (png_ptr->user_chunk_cache_max == 1)
2211 {
2212 png_crc_finish(png_ptr, length);
2213 return;
2214 }
2215 if (--png_ptr->user_chunk_cache_max == 1)
2216 {
2217 png_warning(png_ptr, "No space in chunk cache for iTXt");
2218 png_crc_finish(png_ptr, length);
2219 return;
2220 }
2221 }
2222#endif
2223
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002224 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2225 png_error(png_ptr, "Missing IHDR before iTXt");
2226
2227 if (png_ptr->mode & PNG_HAVE_IDAT)
2228 png_ptr->mode |= PNG_AFTER_IDAT;
2229
2230#ifdef PNG_MAX_MALLOC_64K
2231 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002232 * there is no hard and fast rule to tell us where to stop.
2233 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002234 if (length > (png_uint_32)65535L)
2235 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002236 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2237 png_crc_finish(png_ptr, length);
2238 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002239 }
2240#endif
2241
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002242 png_free(png_ptr, png_ptr->chunkdata);
2243 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2244 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002245 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002246 png_warning(png_ptr, "No memory to process iTXt chunk");
2247 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002248 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002249 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002250 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002251 if (png_crc_finish(png_ptr, 0))
2252 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002253 png_free(png_ptr, png_ptr->chunkdata);
2254 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002255 return;
2256 }
2257
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002258 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002259
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002260 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002261 /* Empty loop */ ;
2262 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002263
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002264 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002265 * translated keyword (possibly empty), and possibly some text after the
2266 * keyword
2267 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002268
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002269 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002270 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002271 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002272 png_free(png_ptr, png_ptr->chunkdata);
2273 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002274 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002275 }
2276 else
2277 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002278 comp_flag = *lang++;
2279 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002280 }
2281
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002282 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002283 /* Empty loop */ ;
2284 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002285
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002286 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002287 {
2288 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002289 png_free(png_ptr, png_ptr->chunkdata);
2290 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002291 return;
2292 }
2293
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002294 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002295 /* Empty loop */ ;
2296 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002297 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002298 {
2299 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002300 png_free(png_ptr, png_ptr->chunkdata);
2301 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002302 return;
2303 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002304
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002305 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002306
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002307 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002308 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002309 png_decompress_chunk(png_ptr, comp_type,
2310 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002311 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002312 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002313 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002314 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002315 if (text_ptr == NULL)
2316 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002317 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2318 png_free(png_ptr, png_ptr->chunkdata);
2319 png_ptr->chunkdata = NULL;
2320 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002321 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002322 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002323 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2324 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002325 text_ptr->itxt_length = data_len;
2326 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002327 text_ptr->key = png_ptr->chunkdata;
2328 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002329
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002330 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002331
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002332 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002333 png_free(png_ptr, png_ptr->chunkdata);
2334 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002335 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002336 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002337}
2338#endif
2339
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002340/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002341 * chunk. If there isn't a problem with the chunk itself (ie bad
2342 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2343 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2344 * case it will be saved away to be written out later.
2345 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002346void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002347png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2348{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002349 png_uint_32 skip = 0;
2350
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002351 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002352
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002353#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002354 if (png_ptr->user_chunk_cache_max != 0)
2355 {
2356 if (png_ptr->user_chunk_cache_max == 1)
2357 {
2358 png_crc_finish(png_ptr, length);
2359 return;
2360 }
2361 if (--png_ptr->user_chunk_cache_max == 1)
2362 {
2363 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2364 png_crc_finish(png_ptr, length);
2365 return;
2366 }
2367 }
2368#endif
2369
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002370 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002371 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002372 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002373 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002374 png_ptr->mode |= PNG_AFTER_IDAT;
2375 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002376
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002377 if (!(png_ptr->chunk_name[0] & 0x20))
2378 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002379#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002380 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002381 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002382#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002383 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002384#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002385 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002386#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002387 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002388 }
2389
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002390#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002391 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002392#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002393 || (png_ptr->read_user_chunk_fn != NULL)
2394#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002395 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002396 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002397#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002398 if (length > (png_uint_32)65535L)
2399 {
2400 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2401 skip = length - (png_uint_32)65535L;
2402 length = (png_uint_32)65535L;
2403 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002404#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002405 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2406 (png_charp)png_ptr->chunk_name,
2407 png_sizeof(png_ptr->unknown_chunk.name));
2408 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2409 = '\0';
2410 png_ptr->unknown_chunk.size = (png_size_t)length;
2411 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002412 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002413 else
2414 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002415 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2416 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002417 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002418#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002419 if (png_ptr->read_user_chunk_fn != NULL)
2420 {
2421 /* Callback to user unknown chunk handler */
2422 int ret;
2423 ret = (*(png_ptr->read_user_chunk_fn))
2424 (png_ptr, &png_ptr->unknown_chunk);
2425 if (ret < 0)
2426 png_chunk_error(png_ptr, "error in user chunk");
2427 if (ret == 0)
2428 {
2429 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002430#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002431 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2432 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002433#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002434 png_chunk_error(png_ptr, "unknown critical chunk");
2435 png_set_unknown_chunks(png_ptr, info_ptr,
2436 &png_ptr->unknown_chunk, 1);
2437 }
2438 }
2439 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002440#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002441 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2442 png_free(png_ptr, png_ptr->unknown_chunk.data);
2443 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002444 }
2445 else
2446#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002447 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002448
2449 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002450
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002451#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002452 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002453#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002454}
2455
2456/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002457 * This function can't have the "critical chunk check" incorporated
2458 * into it, since in the future we will need to be able to call user
2459 * functions to handle unknown critical chunks after we check that
2460 * the chunk name itself is valid.
2461 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002462
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002463#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002464
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002465void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002466png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2467{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002468 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002469 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002470 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002471 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002472 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002473 }
2474}
2475
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002476/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002477 * row. This routine takes care of alpha and transparency if requested.
2478 * This routine also handles the two methods of progressive display
2479 * of interlaced images, depending on the mask value.
2480 * The mask value describes which pixels are to be combined with
2481 * the row. The pattern always repeats every 8 pixels, so just 8
2482 * bits are needed. A one indicates the pixel is to be combined,
2483 * a zero indicates the pixel is to be skipped. This is in addition
2484 * to any alpha or transparency value associated with the pixel. If
2485 * you want all pixels to be combined, pass 0xff (255) in mask.
2486 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002487
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002488void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002489png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002490{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002491 png_debug(1, "in png_combine_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002492 if (mask == 0xff)
2493 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002494 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002495 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002496 }
2497 else
2498 {
2499 switch (png_ptr->row_info.pixel_depth)
2500 {
2501 case 1:
2502 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002503 png_bytep sp = png_ptr->row_buf + 1;
2504 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002505 int s_inc, s_start, s_end;
2506 int m = 0x80;
2507 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002508 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002509 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002510
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002511#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002512 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002513 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002514 s_start = 0;
2515 s_end = 7;
2516 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002517 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002518 else
2519#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002520 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002521 s_start = 7;
2522 s_end = 0;
2523 s_inc = -1;
2524 }
2525
2526 shift = s_start;
2527
2528 for (i = 0; i < row_width; i++)
2529 {
2530 if (m & mask)
2531 {
2532 int value;
2533
2534 value = (*sp >> shift) & 0x01;
2535 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2536 *dp |= (png_byte)(value << shift);
2537 }
2538
2539 if (shift == s_end)
2540 {
2541 shift = s_start;
2542 sp++;
2543 dp++;
2544 }
2545 else
2546 shift += s_inc;
2547
2548 if (m == 1)
2549 m = 0x80;
2550 else
2551 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002552 }
2553 break;
2554 }
2555 case 2:
2556 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002557 png_bytep sp = png_ptr->row_buf + 1;
2558 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002559 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002560 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002561 int shift;
2562 png_uint_32 i;
2563 png_uint_32 row_width = png_ptr->width;
2564 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002565
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002566#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002567 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002568 {
2569 s_start = 0;
2570 s_end = 6;
2571 s_inc = 2;
2572 }
2573 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002574#endif
2575 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002576 s_start = 6;
2577 s_end = 0;
2578 s_inc = -2;
2579 }
2580
2581 shift = s_start;
2582
2583 for (i = 0; i < row_width; i++)
2584 {
2585 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002586 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002587 value = (*sp >> shift) & 0x03;
2588 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2589 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002590 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002591
2592 if (shift == s_end)
2593 {
2594 shift = s_start;
2595 sp++;
2596 dp++;
2597 }
2598 else
2599 shift += s_inc;
2600 if (m == 1)
2601 m = 0x80;
2602 else
2603 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002604 }
2605 break;
2606 }
2607 case 4:
2608 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002609 png_bytep sp = png_ptr->row_buf + 1;
2610 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002611 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002612 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002613 int shift;
2614 png_uint_32 i;
2615 png_uint_32 row_width = png_ptr->width;
2616 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002617
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002618#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002619 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002620 {
2621 s_start = 0;
2622 s_end = 4;
2623 s_inc = 4;
2624 }
2625 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002626#endif
2627 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002628 s_start = 4;
2629 s_end = 0;
2630 s_inc = -4;
2631 }
2632 shift = s_start;
2633
2634 for (i = 0; i < row_width; i++)
2635 {
2636 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002637 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002638 value = (*sp >> shift) & 0xf;
2639 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2640 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002641 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002642
2643 if (shift == s_end)
2644 {
2645 shift = s_start;
2646 sp++;
2647 dp++;
2648 }
2649 else
2650 shift += s_inc;
2651 if (m == 1)
2652 m = 0x80;
2653 else
2654 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002655 }
2656 break;
2657 }
2658 default:
2659 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002660 png_bytep sp = png_ptr->row_buf + 1;
2661 png_bytep dp = row;
2662 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2663 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002664 png_uint_32 row_width = png_ptr->width;
2665 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002666
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002667
2668 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002669 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002670 if (m & mask)
2671 {
2672 png_memcpy(dp, sp, pixel_bytes);
2673 }
2674
2675 sp += pixel_bytes;
2676 dp += pixel_bytes;
2677
2678 if (m == 1)
2679 m = 0x80;
2680 else
2681 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002682 }
2683 break;
2684 }
2685 }
2686 }
2687}
2688
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002689#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002690void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002691png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002692{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002693 png_row_infop row_info = &(png_ptr->row_info);
2694 png_bytep row = png_ptr->row_buf + 1;
2695 int pass = png_ptr->pass;
2696 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002697 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2698 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002699 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002700
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002701 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002702 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002703 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002704 png_uint_32 final_width;
2705
2706 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002707
2708 switch (row_info->pixel_depth)
2709 {
2710 case 1:
2711 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002712 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2713 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002714 int sshift, dshift;
2715 int s_start, s_end, s_inc;
2716 int jstop = png_pass_inc[pass];
2717 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002718 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002719 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002720
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002721#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002722 if (transformations & PNG_PACKSWAP)
2723 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002724 sshift = (int)((row_info->width + 7) & 0x07);
2725 dshift = (int)((final_width + 7) & 0x07);
2726 s_start = 7;
2727 s_end = 0;
2728 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002729 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002730 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002731#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002732 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002733 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2734 dshift = 7 - (int)((final_width + 7) & 0x07);
2735 s_start = 0;
2736 s_end = 7;
2737 s_inc = 1;
2738 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002739
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002740 for (i = 0; i < row_info->width; i++)
2741 {
2742 v = (png_byte)((*sp >> sshift) & 0x01);
2743 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002744 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002745 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2746 *dp |= (png_byte)(v << dshift);
2747 if (dshift == s_end)
2748 {
2749 dshift = s_start;
2750 dp--;
2751 }
2752 else
2753 dshift += s_inc;
2754 }
2755 if (sshift == s_end)
2756 {
2757 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002758 sp--;
2759 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002760 else
2761 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002762 }
2763 break;
2764 }
2765 case 2:
2766 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002767 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2768 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2769 int sshift, dshift;
2770 int s_start, s_end, s_inc;
2771 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002772 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002773
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002774#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002775 if (transformations & PNG_PACKSWAP)
2776 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002777 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2778 dshift = (int)(((final_width + 3) & 0x03) << 1);
2779 s_start = 6;
2780 s_end = 0;
2781 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002782 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002783 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002784#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002785 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002786 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2787 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2788 s_start = 0;
2789 s_end = 6;
2790 s_inc = 2;
2791 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002792
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002793 for (i = 0; i < row_info->width; i++)
2794 {
2795 png_byte v;
2796 int j;
2797
2798 v = (png_byte)((*sp >> sshift) & 0x03);
2799 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002800 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002801 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2802 *dp |= (png_byte)(v << dshift);
2803 if (dshift == s_end)
2804 {
2805 dshift = s_start;
2806 dp--;
2807 }
2808 else
2809 dshift += s_inc;
2810 }
2811 if (sshift == s_end)
2812 {
2813 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002814 sp--;
2815 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002816 else
2817 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002818 }
2819 break;
2820 }
2821 case 4:
2822 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002823 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2824 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002825 int sshift, dshift;
2826 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002827 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002828 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002829
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002830#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002831 if (transformations & PNG_PACKSWAP)
2832 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002833 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2834 dshift = (int)(((final_width + 1) & 0x01) << 2);
2835 s_start = 4;
2836 s_end = 0;
2837 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002838 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002839 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002840#endif
2841 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002842 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2843 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2844 s_start = 0;
2845 s_end = 4;
2846 s_inc = 4;
2847 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002848
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002849 for (i = 0; i < row_info->width; i++)
2850 {
2851 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2852 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002853
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002854 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002855 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002856 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2857 *dp |= (png_byte)(v << dshift);
2858 if (dshift == s_end)
2859 {
2860 dshift = s_start;
2861 dp--;
2862 }
2863 else
2864 dshift += s_inc;
2865 }
2866 if (sshift == s_end)
2867 {
2868 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002869 sp--;
2870 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002871 else
2872 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002873 }
2874 break;
2875 }
2876 default:
2877 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002878 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002879 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2880 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002881 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002882
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002883 int jstop = png_pass_inc[pass];
2884 png_uint_32 i;
2885
2886 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002887 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002888 png_byte v[8];
2889 int j;
2890
2891 png_memcpy(v, sp, pixel_bytes);
2892 for (j = 0; j < jstop; j++)
2893 {
2894 png_memcpy(dp, v, pixel_bytes);
2895 dp -= pixel_bytes;
2896 }
2897 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002898 }
2899 break;
2900 }
2901 }
2902 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002903 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002904 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002905#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002906 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002907#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002908}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002909#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002910
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002911void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002912png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002913 png_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002914{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002915 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06002916 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002917 switch (filter)
2918 {
2919 case PNG_FILTER_VALUE_NONE:
2920 break;
2921 case PNG_FILTER_VALUE_SUB:
2922 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002923 png_uint_32 i;
2924 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002925 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002926 png_bytep rp = row + bpp;
2927 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002928
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002929 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002930 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002931 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2932 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002933 }
2934 break;
2935 }
2936 case PNG_FILTER_VALUE_UP:
2937 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002938 png_uint_32 i;
2939 png_uint_32 istop = row_info->rowbytes;
2940 png_bytep rp = row;
2941 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002942
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002943 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002944 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002945 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2946 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002947 }
2948 break;
2949 }
2950 case PNG_FILTER_VALUE_AVG:
2951 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002952 png_uint_32 i;
2953 png_bytep rp = row;
2954 png_bytep pp = prev_row;
2955 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002956 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002957 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002958
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002959 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002960 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002961 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002962 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002963 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002964 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002965
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002966 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002967 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002968 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002969 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002970 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002971 }
2972 break;
2973 }
2974 case PNG_FILTER_VALUE_PAETH:
2975 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002976 png_uint_32 i;
2977 png_bytep rp = row;
2978 png_bytep pp = prev_row;
2979 png_bytep lp = row;
2980 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002981 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002982 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002983
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002984 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002985 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002986 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2987 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002988 }
2989
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002990 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002991 {
2992 int a, b, c, pa, pb, pc, p;
2993
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002994 a = *lp++;
2995 b = *pp++;
2996 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002997
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002998 p = b - c;
2999 pc = a - c;
3000
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003001#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003002 pa = abs(p);
3003 pb = abs(pc);
3004 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003005#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003006 pa = p < 0 ? -p : p;
3007 pb = pc < 0 ? -pc : pc;
3008 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003009#endif
3010
3011 /*
3012 if (pa <= pb && pa <= pc)
3013 p = a;
3014 else if (pb <= pc)
3015 p = b;
3016 else
3017 p = c;
3018 */
3019
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003020 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003021
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003022 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3023 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003024 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003025 break;
3026 }
3027 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003028 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003029 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003030 break;
3031 }
3032}
Guy Schalnat0d580581995-07-20 02:43:20 -05003033
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003034#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003035void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003036png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003037{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003038#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003039 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003040
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003041 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003042 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003043
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003044 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003045 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003046
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003047 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003048 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003049
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003050 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003051 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3052#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003053
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003054 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003055 png_ptr->row_number++;
3056 if (png_ptr->row_number < png_ptr->num_rows)
3057 return;
3058
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003059#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003060 if (png_ptr->interlaced)
3061 {
3062 png_ptr->row_number = 0;
Glenn Randers-Pehrsona31c74f2009-05-18 15:52:01 -05003063 png_memset(png_ptr->prev_row, 0,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003064 png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003065 do
3066 {
3067 png_ptr->pass++;
3068 if (png_ptr->pass >= 7)
3069 break;
3070 png_ptr->iwidth = (png_ptr->width +
3071 png_pass_inc[png_ptr->pass] - 1 -
3072 png_pass_start[png_ptr->pass]) /
3073 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003074
Guy Schalnat0d580581995-07-20 02:43:20 -05003075 if (!(png_ptr->transformations & PNG_INTERLACE))
3076 {
3077 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003078 png_pass_yinc[png_ptr->pass] - 1 -
3079 png_pass_ystart[png_ptr->pass]) /
3080 png_pass_yinc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003081 if (!(png_ptr->num_rows))
3082 continue;
3083 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003084 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003085 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003086 } while (png_ptr->iwidth == 0);
3087
3088 if (png_ptr->pass < 7)
3089 return;
3090 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003091#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003092
Guy Schalnate5a37791996-06-05 15:50:50 -05003093 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003094 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003095 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003096 char extra;
3097 int ret;
3098
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003099 png_ptr->zstream.next_out = (Byte *)&extra;
3100 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003101 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003102 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003103 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003104 {
3105 while (!png_ptr->idat_size)
3106 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003107 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003108
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003109 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003110
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003111 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003112 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003113 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003114 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003115 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003116 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003117
3118 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003119 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3120 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003122 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3123 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3124 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003125 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003126 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05003127 if (ret == Z_STREAM_END)
3128 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003129 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003130 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003131 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003132 png_ptr->mode |= PNG_AFTER_IDAT;
3133 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003134 break;
3135 }
3136 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003137 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003138 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003139
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003140 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003141 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003142 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003143 png_ptr->mode |= PNG_AFTER_IDAT;
3144 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3145 break;
3146 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003147
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003148 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003149 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003150 }
3151
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003152 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003153 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003154
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003155 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003156
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003157 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003158}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003159#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003160
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003161void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003162png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003163{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003164#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003165 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003166
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003167 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003168 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003169
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003170 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003171 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003172
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003173 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003174 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003175
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003176 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003177 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3178#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003179
Guy Schalnat0d580581995-07-20 02:43:20 -05003180 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003181 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003182
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003183 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003184 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003185 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003186#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003187 if (png_ptr->interlaced)
3188 {
3189 if (!(png_ptr->transformations & PNG_INTERLACE))
3190 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003191 png_pass_ystart[0]) / png_pass_yinc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05003192 else
3193 png_ptr->num_rows = png_ptr->height;
3194
3195 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003196 png_pass_inc[png_ptr->pass] - 1 -
3197 png_pass_start[png_ptr->pass]) /
3198 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003199 }
3200 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003201#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003202 {
3203 png_ptr->num_rows = png_ptr->height;
3204 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003205 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003206 max_pixel_depth = png_ptr->pixel_depth;
3207
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003208#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003209 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003210 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003211#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003212
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003213#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003214 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003215 {
3216 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3217 {
3218 if (png_ptr->num_trans)
3219 max_pixel_depth = 32;
3220 else
3221 max_pixel_depth = 24;
3222 }
3223 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3224 {
3225 if (max_pixel_depth < 8)
3226 max_pixel_depth = 8;
3227 if (png_ptr->num_trans)
3228 max_pixel_depth *= 2;
3229 }
3230 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3231 {
3232 if (png_ptr->num_trans)
3233 {
3234 max_pixel_depth *= 4;
3235 max_pixel_depth /= 3;
3236 }
3237 }
3238 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003239#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003240
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003241#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003242 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003243 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003244 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3245 max_pixel_depth = 32;
3246 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003247 {
3248 if (max_pixel_depth <= 8)
3249 max_pixel_depth = 16;
3250 else
3251 max_pixel_depth = 32;
3252 }
3253 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3254 {
3255 if (max_pixel_depth <= 32)
3256 max_pixel_depth = 32;
3257 else
3258 max_pixel_depth = 64;
3259 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003260 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003261#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003262
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003263#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003264 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3265 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003266 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003267#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003268 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003269#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003270#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003271 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003272#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003273 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003274 {
3275 if (max_pixel_depth <= 16)
3276 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003277 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003278 max_pixel_depth = 64;
3279 }
3280 else
3281 {
3282 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003283 {
3284 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003285 max_pixel_depth = 32;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003286 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003287 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003288 }
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003289 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3290 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003291 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003292 max_pixel_depth = 48;
3293 }
3294 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003295#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003296
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003297#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3298defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003299 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003300 {
3301 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003302 png_ptr->user_transform_channels;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003303 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003304 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003305 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003306#endif
3307
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003308 /* Align the width on the next larger 8 pixels. Mainly used
3309 * for interlacing
3310 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003311 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003312 /* Calculate the maximum bytes needed, adding a byte and a pixel
3313 * for safety's sake
3314 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003315 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003316 1 + ((max_pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003317#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003318 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003319 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003320#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003321
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003322 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003323 {
3324 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003325 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003326 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3327 row_bytes + 48);
3328 else
3329 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3330 row_bytes + 48);
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003331 png_ptr->old_big_row_buf_size = row_bytes + 48;
3332
3333#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3334 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3335 * of padding before and after row_buf.
3336 */
3337 png_ptr->row_buf = png_ptr->big_row_buf + 32
3338 - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16);
3339 png_ptr->old_big_row_buf_size = row_bytes + 48;
3340#else
3341 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003342 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003343#endif
3344 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003345 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003346
3347#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003348 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003349 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003350#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003351 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003352 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003353
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003354 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003355 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003356 png_free(png_ptr, png_ptr->prev_row);
3357 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003358 png_ptr->rowbytes + 1));
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003359 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003360 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003361
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003362 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003363
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003364 png_debug1(3, "width = %u,", png_ptr->width);
3365 png_debug1(3, "height = %u,", png_ptr->height);
3366 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3367 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3368 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3369 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003370 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003371
Guy Schalnate5a37791996-06-05 15:50:50 -05003372 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003373}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003374#endif /* PNG_READ_SUPPORTED */