blob: 72bd01a3576fcca8a7dac42742f75c37d5708273 [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-Pehrson92a3ef42010-03-31 21:50:21 -05004 * Last changed in libpng 1.4.1 [April 1, 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-Pehrson9b0956f2010-02-12 11:17:22 -06001136#ifdef PNG_STDIO_SUPPORTED
1137 {
Glenn Randers-Pehrson92a3ef42010-03-31 21:50:21 -05001138 char umsg[80];
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001139
Glenn Randers-Pehrson92a3ef42010-03-31 21:50:21 -05001140 png_snprintf2(umsg, 80,
1141 "Ignoring iCCP chunk with declared size = %lu "
1142 "and actual length = %lu",
1143 (unsigned long)profile_size,
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -06001144 (unsigned long)profile_length);
1145 png_warning(png_ptr, umsg);
1146 }
1147#endif
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001148 return;
1149 }
1150
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001151 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001152 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001153 png_free(png_ptr, png_ptr->chunkdata);
1154 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001155}
1156#endif /* PNG_READ_iCCP_SUPPORTED */
1157
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001158#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001159void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001160png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1161/* Note: this does not properly handle chunks that are > 64K under DOS */
1162{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001163 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001164 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001165#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001166 png_sPLT_entryp pp;
1167#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001168 int data_length, entry_size, i;
1169 png_uint_32 skip = 0;
1170 png_size_t slength;
1171
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001172 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001173
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001174#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001175
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001176 if (png_ptr->user_chunk_cache_max != 0)
1177 {
1178 if (png_ptr->user_chunk_cache_max == 1)
1179 {
1180 png_crc_finish(png_ptr, length);
1181 return;
1182 }
1183 if (--png_ptr->user_chunk_cache_max == 1)
1184 {
1185 png_warning(png_ptr, "No space in chunk cache for sPLT");
1186 png_crc_finish(png_ptr, length);
1187 return;
1188 }
1189 }
1190#endif
1191
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001192 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1193 png_error(png_ptr, "Missing IHDR before sPLT");
1194 else if (png_ptr->mode & PNG_HAVE_IDAT)
1195 {
1196 png_warning(png_ptr, "Invalid sPLT after IDAT");
1197 png_crc_finish(png_ptr, length);
1198 return;
1199 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001200
1201#ifdef PNG_MAX_MALLOC_64K
1202 if (length > (png_uint_32)65535L)
1203 {
1204 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1205 skip = length - (png_uint_32)65535L;
1206 length = (png_uint_32)65535L;
1207 }
1208#endif
1209
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001210 png_free(png_ptr, png_ptr->chunkdata);
1211 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001212 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001213 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001214
1215 if (png_crc_finish(png_ptr, skip))
1216 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001217 png_free(png_ptr, png_ptr->chunkdata);
1218 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001219 return;
1220 }
1221
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001222 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001223
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001224 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1225 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001226 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001227 ++entry_start;
1228
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001229 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001230 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001231 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001232 png_free(png_ptr, png_ptr->chunkdata);
1233 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001234 png_warning(png_ptr, "malformed sPLT chunk");
1235 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001236 }
1237
1238 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001239 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001240 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001241
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001242 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001243 if (data_length % entry_size)
1244 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001245 png_free(png_ptr, png_ptr->chunkdata);
1246 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001247 png_warning(png_ptr, "sPLT chunk has bad length");
1248 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001249 }
1250
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001251 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001252 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001253 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001254 {
1255 png_warning(png_ptr, "sPLT chunk too long");
1256 return;
1257 }
1258 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001259 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001260 if (new_palette.entries == NULL)
1261 {
1262 png_warning(png_ptr, "sPLT chunk requires too much memory");
1263 return;
1264 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001265
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001266#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001267 for (i = 0; i < new_palette.nentries; i++)
1268 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001269 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001270
1271 if (new_palette.depth == 8)
1272 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001273 pp->red = *entry_start++;
1274 pp->green = *entry_start++;
1275 pp->blue = *entry_start++;
1276 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001277 }
1278 else
1279 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001280 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1281 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1282 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1283 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001284 }
1285 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1286 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001287#else
1288 pp = new_palette.entries;
1289 for (i = 0; i < new_palette.nentries; i++)
1290 {
1291
1292 if (new_palette.depth == 8)
1293 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001294 pp[i].red = *entry_start++;
1295 pp[i].green = *entry_start++;
1296 pp[i].blue = *entry_start++;
1297 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001298 }
1299 else
1300 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001301 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1302 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1303 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1304 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001305 }
1306 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1307 }
1308#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001309
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001310 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001311 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001312
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001313 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001314
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001315 png_free(png_ptr, png_ptr->chunkdata);
1316 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001317 png_free(png_ptr, new_palette.entries);
1318}
1319#endif /* PNG_READ_sPLT_SUPPORTED */
1320
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001321#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001322void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001323png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001324{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001325 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001326
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001327 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001328
Guy Schalnate5a37791996-06-05 15:50:50 -05001329 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1330 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001331 else if (png_ptr->mode & PNG_HAVE_IDAT)
1332 {
1333 png_warning(png_ptr, "Invalid tRNS after IDAT");
1334 png_crc_finish(png_ptr, length);
1335 return;
1336 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001337 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001338 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001339 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001340 png_crc_finish(png_ptr, length);
1341 return;
1342 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001343
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001344 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001345 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001346 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001347
1348 if (length != 2)
1349 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001350 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001351 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001352 return;
1353 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001354
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001355 png_crc_read(png_ptr, buf, 2);
1356 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001357 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001358 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001359 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1360 {
1361 png_byte buf[6];
1362
1363 if (length != 6)
1364 {
1365 png_warning(png_ptr, "Incorrect tRNS chunk length");
1366 png_crc_finish(png_ptr, length);
1367 return;
1368 }
1369 png_crc_read(png_ptr, buf, (png_size_t)length);
1370 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001371 png_ptr->trans_color.red = png_get_uint_16(buf);
1372 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1373 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001374 }
1375 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1376 {
1377 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1378 {
1379 /* Should be an error, but we can cope with it. */
1380 png_warning(png_ptr, "Missing PLTE before tRNS");
1381 }
1382 if (length > (png_uint_32)png_ptr->num_palette ||
1383 length > PNG_MAX_PALETTE_LENGTH)
1384 {
1385 png_warning(png_ptr, "Incorrect tRNS chunk length");
1386 png_crc_finish(png_ptr, length);
1387 return;
1388 }
1389 if (length == 0)
1390 {
1391 png_warning(png_ptr, "Zero length tRNS chunk");
1392 png_crc_finish(png_ptr, length);
1393 return;
1394 }
1395 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1396 png_ptr->num_trans = (png_uint_16)length;
1397 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001398 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001399 {
1400 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001401 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001402 return;
1403 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001404
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001405 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001406 {
1407 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001408 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001409 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001410
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001411 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001412 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001413}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001414#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001415
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001416#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001417void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001418png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001419{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001420 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001421 png_byte buf[6];
1422
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001423 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001424
Guy Schalnate5a37791996-06-05 15:50:50 -05001425 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1426 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001427 else if (png_ptr->mode & PNG_HAVE_IDAT)
1428 {
1429 png_warning(png_ptr, "Invalid bKGD after IDAT");
1430 png_crc_finish(png_ptr, length);
1431 return;
1432 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001433 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001434 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001435 {
1436 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001437 png_crc_finish(png_ptr, length);
1438 return;
1439 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001440 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001441 {
1442 png_warning(png_ptr, "Duplicate bKGD chunk");
1443 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001444 return;
1445 }
1446
Guy Schalnat0d580581995-07-20 02:43:20 -05001447 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1448 truelen = 1;
1449 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1450 truelen = 6;
1451 else
1452 truelen = 2;
1453
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001454 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001455 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001456 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001457 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001458 return;
1459 }
1460
Andreas Dilger47a0c421997-05-16 02:46:07 -05001461 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001462 if (png_crc_finish(png_ptr, 0))
1463 return;
1464
Guy Schalnate5a37791996-06-05 15:50:50 -05001465 /* We convert the index value into RGB components so that we can allow
1466 * arbitrary RGB values for background when we have transparency, and
1467 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001468 * from the info_ptr struct.
1469 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001470 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001471 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001472 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001473 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001474 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001475 if (buf[0] >= info_ptr->num_palette)
1476 {
1477 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1478 return;
1479 }
1480 png_ptr->background.red =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001481 (png_uint_16)png_ptr->palette[buf[0]].red;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001482 png_ptr->background.green =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001483 (png_uint_16)png_ptr->palette[buf[0]].green;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001484 png_ptr->background.blue =
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001485 (png_uint_16)png_ptr->palette[buf[0]].blue;
1486 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001487 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001488 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001489 {
1490 png_ptr->background.red =
1491 png_ptr->background.green =
1492 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001493 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001494 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001495 else
1496 {
1497 png_ptr->background.red = png_get_uint_16(buf);
1498 png_ptr->background.green = png_get_uint_16(buf + 2);
1499 png_ptr->background.blue = png_get_uint_16(buf + 4);
1500 }
1501
Andreas Dilger47a0c421997-05-16 02:46:07 -05001502 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001503}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001504#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001505
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001506#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001507void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001508png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001509{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001510 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001511 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001512
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001513 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001514
Guy Schalnate5a37791996-06-05 15:50:50 -05001515 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1516 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001517 else if (png_ptr->mode & PNG_HAVE_IDAT)
1518 {
1519 png_warning(png_ptr, "Invalid hIST after IDAT");
1520 png_crc_finish(png_ptr, length);
1521 return;
1522 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001523 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1524 {
1525 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001526 png_crc_finish(png_ptr, length);
1527 return;
1528 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001529 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001530 {
1531 png_warning(png_ptr, "Duplicate hIST chunk");
1532 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001533 return;
1534 }
1535
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001536 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001537 if (num != (unsigned int) png_ptr->num_palette || num >
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001538 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001539 {
1540 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001541 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001542 return;
1543 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001544
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001545 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001546 {
1547 png_byte buf[2];
1548
1549 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001550 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001551 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001552
1553 if (png_crc_finish(png_ptr, 0))
1554 return;
1555
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001556 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001557}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001558#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001559
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001560#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001561void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001562png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001563{
1564 png_byte buf[9];
1565 png_uint_32 res_x, res_y;
1566 int unit_type;
1567
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001568 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001569
Guy Schalnate5a37791996-06-05 15:50:50 -05001570 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001571 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001572 else if (png_ptr->mode & PNG_HAVE_IDAT)
1573 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001574 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001575 png_crc_finish(png_ptr, length);
1576 return;
1577 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001578 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001579 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001580 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001581 png_crc_finish(png_ptr, length);
1582 return;
1583 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001584
Guy Schalnat0d580581995-07-20 02:43:20 -05001585 if (length != 9)
1586 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001587 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001588 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001589 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001590 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001591
1592 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001593 if (png_crc_finish(png_ptr, 0))
1594 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001595
1596 res_x = png_get_uint_32(buf);
1597 res_y = png_get_uint_32(buf + 4);
1598 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001599 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001600}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001601#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001602
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001603#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001604void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001605png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001606{
1607 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001608 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001609 int unit_type;
1610
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001611 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001612
Guy Schalnate5a37791996-06-05 15:50:50 -05001613 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1614 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001615 else if (png_ptr->mode & PNG_HAVE_IDAT)
1616 {
1617 png_warning(png_ptr, "Invalid oFFs after IDAT");
1618 png_crc_finish(png_ptr, length);
1619 return;
1620 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001621 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001622 {
1623 png_warning(png_ptr, "Duplicate oFFs chunk");
1624 png_crc_finish(png_ptr, length);
1625 return;
1626 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001627
Guy Schalnat0d580581995-07-20 02:43:20 -05001628 if (length != 9)
1629 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001630 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001631 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001632 return;
1633 }
1634
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001635 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001636 if (png_crc_finish(png_ptr, 0))
1637 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001638
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001639 offset_x = png_get_int_32(buf);
1640 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001641 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001642 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1643}
1644#endif
1645
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001646#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001647/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001648void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001649png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1650{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001651 png_int_32 X0, X1;
1652 png_byte type, nparams;
1653 png_charp buf, units, endptr;
1654 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001655 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001656 int i;
1657
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001658 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001659
1660 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1661 png_error(png_ptr, "Missing IHDR before pCAL");
1662 else if (png_ptr->mode & PNG_HAVE_IDAT)
1663 {
1664 png_warning(png_ptr, "Invalid pCAL after IDAT");
1665 png_crc_finish(png_ptr, length);
1666 return;
1667 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001668 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001669 {
1670 png_warning(png_ptr, "Duplicate pCAL chunk");
1671 png_crc_finish(png_ptr, length);
1672 return;
1673 }
1674
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001675 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001676 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001677 png_free(png_ptr, png_ptr->chunkdata);
1678 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1679 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001680 {
1681 png_warning(png_ptr, "No memory for pCAL purpose");
1682 return;
1683 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001684 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001685 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001686
1687 if (png_crc_finish(png_ptr, 0))
1688 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001689 png_free(png_ptr, png_ptr->chunkdata);
1690 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001691 return;
1692 }
1693
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001694 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001696 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001697 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001698 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001699
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001700 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001701
1702 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001703 * in order to get the parameter information.
1704 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001705 if (endptr <= buf + 12)
1706 {
1707 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001708 png_free(png_ptr, png_ptr->chunkdata);
1709 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001710 return;
1711 }
1712
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001713 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001714 X0 = png_get_int_32((png_bytep)buf+1);
1715 X1 = png_get_int_32((png_bytep)buf+5);
1716 type = buf[9];
1717 nparams = buf[10];
1718 units = buf + 11;
1719
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001720 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001721 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001722 * equation types.
1723 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001724 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1725 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1726 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1727 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1728 {
1729 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001730 png_free(png_ptr, png_ptr->chunkdata);
1731 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001732 return;
1733 }
1734 else if (type >= PNG_EQUATION_LAST)
1735 {
1736 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1737 }
1738
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001739 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001740 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001741
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001742 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001743 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001744 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001745 if (params == NULL)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001746 {
1747 png_free(png_ptr, png_ptr->chunkdata);
1748 png_ptr->chunkdata = NULL;
1749 png_warning(png_ptr, "No memory for pCAL params");
1750 return;
1751 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001752
1753 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001754 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001755 {
1756 buf++; /* Skip the null string terminator from previous parameter. */
1757
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001758 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001759 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001760 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001761
1762 /* Make sure we haven't run out of data yet */
1763 if (buf > endptr)
1764 {
1765 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001766 png_free(png_ptr, png_ptr->chunkdata);
1767 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001768 png_free(png_ptr, params);
1769 return;
1770 }
1771 }
1772
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001773 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001774 units, params);
1775
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001776 png_free(png_ptr, png_ptr->chunkdata);
1777 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001778 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001779}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001780#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001781
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001782#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001783/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001784void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001785png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1786{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001787 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001788#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001789 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001790 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001791#else
1792#ifdef PNG_FIXED_POINT_SUPPORTED
1793 png_charp swidth, sheight;
1794#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001795#endif
1796 png_size_t slength;
1797
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001798 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001799
1800 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1801 png_error(png_ptr, "Missing IHDR before sCAL");
1802 else if (png_ptr->mode & PNG_HAVE_IDAT)
1803 {
1804 png_warning(png_ptr, "Invalid sCAL after IDAT");
1805 png_crc_finish(png_ptr, length);
1806 return;
1807 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001808 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001809 {
1810 png_warning(png_ptr, "Duplicate sCAL chunk");
1811 png_crc_finish(png_ptr, length);
1812 return;
1813 }
1814
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06001815 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001816 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001817 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1818 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001819 {
1820 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1821 return;
1822 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001823 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001824 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001825
1826 if (png_crc_finish(png_ptr, 0))
1827 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001828 png_free(png_ptr, png_ptr->chunkdata);
1829 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001830 return;
1831 }
1832
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001833 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001834
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001835 ep = png_ptr->chunkdata + 1; /* Skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001836
1837#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001838 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001839 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001840 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001841 png_warning(png_ptr, "malformed width string in sCAL chunk");
1842 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001843 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001844#else
1845#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001846 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1847 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001848 {
1849 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1850 return;
1851 }
1852 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001853#endif
1854#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001855
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001856 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001857 /* Empty loop */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001858 ep++;
1859
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001860 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001861 {
1862 png_warning(png_ptr, "Truncated sCAL chunk");
1863#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1864 !defined(PNG_FLOATING_POINT_SUPPORTED)
1865 png_free(png_ptr, swidth);
1866#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001867 png_free(png_ptr, png_ptr->chunkdata);
1868 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001869 return;
1870 }
1871
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001872#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001873 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001874 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001875 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001876 png_warning(png_ptr, "malformed height string in sCAL chunk");
1877 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001878 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001879#else
1880#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001881 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001882 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001883 {
1884 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1885 return;
1886 }
1887 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001888#endif
1889#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001890
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001891 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001892#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001893 || width <= 0. || height <= 0.
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001894#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06001895 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001896 {
1897 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001898 png_free(png_ptr, png_ptr->chunkdata);
1899 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001900#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001901 png_free(png_ptr, swidth);
1902 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001903#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001904 return;
1905 }
1906
1907
1908#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001909 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001910#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001911#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001912 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001913#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001914#endif
1915
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001916 png_free(png_ptr, png_ptr->chunkdata);
1917 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001918#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1919 png_free(png_ptr, swidth);
1920 png_free(png_ptr, sheight);
1921#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001922}
1923#endif
1924
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001925#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001926void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001927png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001928{
1929 png_byte buf[7];
1930 png_time mod_time;
1931
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001932 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001933
Guy Schalnate5a37791996-06-05 15:50:50 -05001934 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001935 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001936 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001937 {
1938 png_warning(png_ptr, "Duplicate tIME chunk");
1939 png_crc_finish(png_ptr, length);
1940 return;
1941 }
1942
1943 if (png_ptr->mode & PNG_HAVE_IDAT)
1944 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001945
Guy Schalnat0d580581995-07-20 02:43:20 -05001946 if (length != 7)
1947 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001948 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001949 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001950 return;
1951 }
1952
1953 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001954 if (png_crc_finish(png_ptr, 0))
1955 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001956
1957 mod_time.second = buf[6];
1958 mod_time.minute = buf[5];
1959 mod_time.hour = buf[4];
1960 mod_time.day = buf[3];
1961 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001962 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001963
Andreas Dilger47a0c421997-05-16 02:46:07 -05001964 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001965}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001966#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001967
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001968#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001969/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001970void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001971png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001972{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001973 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001974 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001975 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001976 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001977 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001978 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001979
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001980 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05001981
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001982#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001983 if (png_ptr->user_chunk_cache_max != 0)
1984 {
1985 if (png_ptr->user_chunk_cache_max == 1)
1986 {
1987 png_crc_finish(png_ptr, length);
1988 return;
1989 }
1990 if (--png_ptr->user_chunk_cache_max == 1)
1991 {
1992 png_warning(png_ptr, "No space in chunk cache for tEXt");
1993 png_crc_finish(png_ptr, length);
1994 return;
1995 }
1996 }
1997#endif
1998
Guy Schalnate5a37791996-06-05 15:50:50 -05001999 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2000 png_error(png_ptr, "Missing IHDR before tEXt");
2001
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002002 if (png_ptr->mode & PNG_HAVE_IDAT)
2003 png_ptr->mode |= PNG_AFTER_IDAT;
2004
Andreas Dilger47a0c421997-05-16 02:46:07 -05002005#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002006 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002007 {
2008 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002009 skip = length - (png_uint_32)65535L;
2010 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002011 }
2012#endif
2013
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002014 png_free(png_ptr, png_ptr->chunkdata);
2015
2016 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2017 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002018 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002019 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002020 return;
2021 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002022 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002023 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002024
2025 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002026 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002027 png_free(png_ptr, png_ptr->chunkdata);
2028 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002029 return;
2030 }
2031
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002032 key = png_ptr->chunkdata;
2033
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002034 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002035
2036 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002037 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002038
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002039 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002040 text++;
2041
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002042 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002043 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002044 if (text_ptr == NULL)
2045 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002046 png_warning(png_ptr, "Not enough memory to process text chunk");
2047 png_free(png_ptr, png_ptr->chunkdata);
2048 png_ptr->chunkdata = NULL;
2049 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002050 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002051 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2052 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002053 text_ptr->lang = NULL;
2054 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002055 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002056 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002057 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002058
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002059 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002060
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002061 png_free(png_ptr, png_ptr->chunkdata);
2062 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002063 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002064 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002065 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002066}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002067#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002068
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002069#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002070/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002071void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002072png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002073{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002074 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002075 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002076 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002077 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002078 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002079
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002080 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002081
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002082#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002083 if (png_ptr->user_chunk_cache_max != 0)
2084 {
2085 if (png_ptr->user_chunk_cache_max == 1)
2086 {
2087 png_crc_finish(png_ptr, length);
2088 return;
2089 }
2090 if (--png_ptr->user_chunk_cache_max == 1)
2091 {
2092 png_warning(png_ptr, "No space in chunk cache for zTXt");
2093 png_crc_finish(png_ptr, length);
2094 return;
2095 }
2096 }
2097#endif
2098
Guy Schalnate5a37791996-06-05 15:50:50 -05002099 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2100 png_error(png_ptr, "Missing IHDR before zTXt");
2101
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002102 if (png_ptr->mode & PNG_HAVE_IDAT)
2103 png_ptr->mode |= PNG_AFTER_IDAT;
2104
Andreas Dilger47a0c421997-05-16 02:46:07 -05002105#ifdef PNG_MAX_MALLOC_64K
2106 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002107 * there is no hard and fast rule to tell us where to stop.
2108 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002109 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002110 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002111 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2112 png_crc_finish(png_ptr, length);
2113 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002114 }
2115#endif
2116
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002117 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002118 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2119 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002120 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002121 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2122 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002123 }
2124 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002125 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002126 if (png_crc_finish(png_ptr, 0))
2127 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002128 png_free(png_ptr, png_ptr->chunkdata);
2129 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002130 return;
2131 }
2132
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002133 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002134
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002135 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002136 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002137
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002138 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002139 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002140 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002141 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002142 png_free(png_ptr, png_ptr->chunkdata);
2143 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002144 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002145 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002146 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002147 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002148 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002149 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2150 {
2151 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2152 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2153 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002154 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002155 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002156 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002157
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002158 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002159 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002160
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002161 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002162 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002163 if (text_ptr == NULL)
2164 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002165 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2166 png_free(png_ptr, png_ptr->chunkdata);
2167 png_ptr->chunkdata = NULL;
2168 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002169 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002170 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002171 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002172 text_ptr->lang = NULL;
2173 text_ptr->lang_key = NULL;
2174 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002175 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002176 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002177
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002178 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002179
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002180 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002181 png_free(png_ptr, png_ptr->chunkdata);
2182 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002183 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002184 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002185}
2186#endif
2187
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002188#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002189/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002190void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002191png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2192{
2193 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002194 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002195 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002196 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002197 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002198 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002199
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002200 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002201
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002202#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002203 if (png_ptr->user_chunk_cache_max != 0)
2204 {
2205 if (png_ptr->user_chunk_cache_max == 1)
2206 {
2207 png_crc_finish(png_ptr, length);
2208 return;
2209 }
2210 if (--png_ptr->user_chunk_cache_max == 1)
2211 {
2212 png_warning(png_ptr, "No space in chunk cache for iTXt");
2213 png_crc_finish(png_ptr, length);
2214 return;
2215 }
2216 }
2217#endif
2218
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002219 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2220 png_error(png_ptr, "Missing IHDR before iTXt");
2221
2222 if (png_ptr->mode & PNG_HAVE_IDAT)
2223 png_ptr->mode |= PNG_AFTER_IDAT;
2224
2225#ifdef PNG_MAX_MALLOC_64K
2226 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002227 * there is no hard and fast rule to tell us where to stop.
2228 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002229 if (length > (png_uint_32)65535L)
2230 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002231 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2232 png_crc_finish(png_ptr, length);
2233 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002234 }
2235#endif
2236
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002237 png_free(png_ptr, png_ptr->chunkdata);
2238 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2239 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002240 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002241 png_warning(png_ptr, "No memory to process iTXt chunk");
2242 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002243 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002244 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002245 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002246 if (png_crc_finish(png_ptr, 0))
2247 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002248 png_free(png_ptr, png_ptr->chunkdata);
2249 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002250 return;
2251 }
2252
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002253 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002254
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002255 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002256 /* Empty loop */ ;
2257 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002258
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002259 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002260 * translated keyword (possibly empty), and possibly some text after the
2261 * keyword
2262 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002263
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002264 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002265 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002266 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002267 png_free(png_ptr, png_ptr->chunkdata);
2268 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002269 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002270 }
2271 else
2272 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002273 comp_flag = *lang++;
2274 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002275 }
2276
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002277 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002278 /* Empty loop */ ;
2279 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002280
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002281 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002282 {
2283 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002284 png_free(png_ptr, png_ptr->chunkdata);
2285 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002286 return;
2287 }
2288
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002289 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002290 /* Empty loop */ ;
2291 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002292 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002293 {
2294 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002295 png_free(png_ptr, png_ptr->chunkdata);
2296 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002297 return;
2298 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002299
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002300 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002301
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002302 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002303 if (comp_flag)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002304 png_decompress_chunk(png_ptr, comp_type,
2305 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002306 else
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002307 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002308 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002309 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002310 if (text_ptr == NULL)
2311 {
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002312 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2313 png_free(png_ptr, png_ptr->chunkdata);
2314 png_ptr->chunkdata = NULL;
2315 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002316 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002317 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002318 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2319 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002320 text_ptr->itxt_length = data_len;
2321 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002322 text_ptr->key = png_ptr->chunkdata;
2323 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002324
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002325 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002326
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002327 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002328 png_free(png_ptr, png_ptr->chunkdata);
2329 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002330 if (ret)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002331 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002332}
2333#endif
2334
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002335/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002336 * chunk. If there isn't a problem with the chunk itself (ie bad
2337 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2338 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2339 * case it will be saved away to be written out later.
2340 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002341void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002342png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2343{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002344 png_uint_32 skip = 0;
2345
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002346 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002347
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002348#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002349 if (png_ptr->user_chunk_cache_max != 0)
2350 {
2351 if (png_ptr->user_chunk_cache_max == 1)
2352 {
2353 png_crc_finish(png_ptr, length);
2354 return;
2355 }
2356 if (--png_ptr->user_chunk_cache_max == 1)
2357 {
2358 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2359 png_crc_finish(png_ptr, length);
2360 return;
2361 }
2362 }
2363#endif
2364
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002365 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002366 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002367 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002368 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002369 png_ptr->mode |= PNG_AFTER_IDAT;
2370 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002371
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002372 if (!(png_ptr->chunk_name[0] & 0x20))
2373 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002374#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002375 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002376 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002377#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002378 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002379#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002380 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002381#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002382 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002383 }
2384
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002385#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002386 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002387#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002388 || (png_ptr->read_user_chunk_fn != NULL)
2389#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002390 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002391 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002392#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002393 if (length > (png_uint_32)65535L)
2394 {
2395 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2396 skip = length - (png_uint_32)65535L;
2397 length = (png_uint_32)65535L;
2398 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002399#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002400 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2401 (png_charp)png_ptr->chunk_name,
2402 png_sizeof(png_ptr->unknown_chunk.name));
2403 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2404 = '\0';
2405 png_ptr->unknown_chunk.size = (png_size_t)length;
2406 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002407 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002408 else
2409 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002410 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2411 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002412 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002413#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002414 if (png_ptr->read_user_chunk_fn != NULL)
2415 {
2416 /* Callback to user unknown chunk handler */
2417 int ret;
2418 ret = (*(png_ptr->read_user_chunk_fn))
2419 (png_ptr, &png_ptr->unknown_chunk);
2420 if (ret < 0)
2421 png_chunk_error(png_ptr, "error in user chunk");
2422 if (ret == 0)
2423 {
2424 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002425#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002426 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2427 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002428#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002429 png_chunk_error(png_ptr, "unknown critical chunk");
2430 png_set_unknown_chunks(png_ptr, info_ptr,
2431 &png_ptr->unknown_chunk, 1);
2432 }
2433 }
2434 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002435#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002436 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2437 png_free(png_ptr, png_ptr->unknown_chunk.data);
2438 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002439 }
2440 else
2441#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002442 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002443
2444 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002445
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002446#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002447 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002448#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002449}
2450
2451/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002452 * This function can't have the "critical chunk check" incorporated
2453 * into it, since in the future we will need to be able to call user
2454 * functions to handle unknown critical chunks after we check that
2455 * the chunk name itself is valid.
2456 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002457
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002458#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002459
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002460void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002461png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2462{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002463 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002464 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002465 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002466 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002467 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002468 }
2469}
2470
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002471/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002472 * row. This routine takes care of alpha and transparency if requested.
2473 * This routine also handles the two methods of progressive display
2474 * of interlaced images, depending on the mask value.
2475 * The mask value describes which pixels are to be combined with
2476 * the row. The pattern always repeats every 8 pixels, so just 8
2477 * bits are needed. A one indicates the pixel is to be combined,
2478 * a zero indicates the pixel is to be skipped. This is in addition
2479 * to any alpha or transparency value associated with the pixel. If
2480 * you want all pixels to be combined, pass 0xff (255) in mask.
2481 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002482
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002483void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002484png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002485{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002486 png_debug(1, "in png_combine_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002487 if (mask == 0xff)
2488 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002489 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002490 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002491 }
2492 else
2493 {
2494 switch (png_ptr->row_info.pixel_depth)
2495 {
2496 case 1:
2497 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002498 png_bytep sp = png_ptr->row_buf + 1;
2499 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002500 int s_inc, s_start, s_end;
2501 int m = 0x80;
2502 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002503 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002504 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002505
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002506#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002507 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002508 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002509 s_start = 0;
2510 s_end = 7;
2511 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002512 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002513 else
2514#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002515 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002516 s_start = 7;
2517 s_end = 0;
2518 s_inc = -1;
2519 }
2520
2521 shift = s_start;
2522
2523 for (i = 0; i < row_width; i++)
2524 {
2525 if (m & mask)
2526 {
2527 int value;
2528
2529 value = (*sp >> shift) & 0x01;
2530 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2531 *dp |= (png_byte)(value << shift);
2532 }
2533
2534 if (shift == s_end)
2535 {
2536 shift = s_start;
2537 sp++;
2538 dp++;
2539 }
2540 else
2541 shift += s_inc;
2542
2543 if (m == 1)
2544 m = 0x80;
2545 else
2546 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002547 }
2548 break;
2549 }
2550 case 2:
2551 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002552 png_bytep sp = png_ptr->row_buf + 1;
2553 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002554 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002555 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002556 int shift;
2557 png_uint_32 i;
2558 png_uint_32 row_width = png_ptr->width;
2559 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002560
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002561#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002562 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002563 {
2564 s_start = 0;
2565 s_end = 6;
2566 s_inc = 2;
2567 }
2568 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002569#endif
2570 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002571 s_start = 6;
2572 s_end = 0;
2573 s_inc = -2;
2574 }
2575
2576 shift = s_start;
2577
2578 for (i = 0; i < row_width; i++)
2579 {
2580 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002581 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002582 value = (*sp >> shift) & 0x03;
2583 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2584 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002585 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002586
2587 if (shift == s_end)
2588 {
2589 shift = s_start;
2590 sp++;
2591 dp++;
2592 }
2593 else
2594 shift += s_inc;
2595 if (m == 1)
2596 m = 0x80;
2597 else
2598 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002599 }
2600 break;
2601 }
2602 case 4:
2603 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002604 png_bytep sp = png_ptr->row_buf + 1;
2605 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002606 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002607 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002608 int shift;
2609 png_uint_32 i;
2610 png_uint_32 row_width = png_ptr->width;
2611 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002612
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002613#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002614 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002615 {
2616 s_start = 0;
2617 s_end = 4;
2618 s_inc = 4;
2619 }
2620 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002621#endif
2622 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002623 s_start = 4;
2624 s_end = 0;
2625 s_inc = -4;
2626 }
2627 shift = s_start;
2628
2629 for (i = 0; i < row_width; i++)
2630 {
2631 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002632 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002633 value = (*sp >> shift) & 0xf;
2634 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2635 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002636 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002637
2638 if (shift == s_end)
2639 {
2640 shift = s_start;
2641 sp++;
2642 dp++;
2643 }
2644 else
2645 shift += s_inc;
2646 if (m == 1)
2647 m = 0x80;
2648 else
2649 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002650 }
2651 break;
2652 }
2653 default:
2654 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002655 png_bytep sp = png_ptr->row_buf + 1;
2656 png_bytep dp = row;
2657 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2658 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002659 png_uint_32 row_width = png_ptr->width;
2660 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002661
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002662
2663 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002664 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002665 if (m & mask)
2666 {
2667 png_memcpy(dp, sp, pixel_bytes);
2668 }
2669
2670 sp += pixel_bytes;
2671 dp += pixel_bytes;
2672
2673 if (m == 1)
2674 m = 0x80;
2675 else
2676 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002677 }
2678 break;
2679 }
2680 }
2681 }
2682}
2683
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002684#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002685void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002686png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002687{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002688 png_row_infop row_info = &(png_ptr->row_info);
2689 png_bytep row = png_ptr->row_buf + 1;
2690 int pass = png_ptr->pass;
2691 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002692 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2693 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002694 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002695
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002696 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002697 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002698 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002699 png_uint_32 final_width;
2700
2701 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002702
2703 switch (row_info->pixel_depth)
2704 {
2705 case 1:
2706 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002707 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2708 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002709 int sshift, dshift;
2710 int s_start, s_end, s_inc;
2711 int jstop = png_pass_inc[pass];
2712 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002713 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002714 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002715
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002716#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002717 if (transformations & PNG_PACKSWAP)
2718 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002719 sshift = (int)((row_info->width + 7) & 0x07);
2720 dshift = (int)((final_width + 7) & 0x07);
2721 s_start = 7;
2722 s_end = 0;
2723 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002724 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002725 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002726#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002727 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002728 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2729 dshift = 7 - (int)((final_width + 7) & 0x07);
2730 s_start = 0;
2731 s_end = 7;
2732 s_inc = 1;
2733 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002734
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002735 for (i = 0; i < row_info->width; i++)
2736 {
2737 v = (png_byte)((*sp >> sshift) & 0x01);
2738 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002739 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002740 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2741 *dp |= (png_byte)(v << dshift);
2742 if (dshift == s_end)
2743 {
2744 dshift = s_start;
2745 dp--;
2746 }
2747 else
2748 dshift += s_inc;
2749 }
2750 if (sshift == s_end)
2751 {
2752 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002753 sp--;
2754 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002755 else
2756 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002757 }
2758 break;
2759 }
2760 case 2:
2761 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002762 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2763 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2764 int sshift, dshift;
2765 int s_start, s_end, s_inc;
2766 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002767 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002768
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002769#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002770 if (transformations & PNG_PACKSWAP)
2771 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002772 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2773 dshift = (int)(((final_width + 3) & 0x03) << 1);
2774 s_start = 6;
2775 s_end = 0;
2776 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002777 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002778 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002779#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002780 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002781 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2782 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2783 s_start = 0;
2784 s_end = 6;
2785 s_inc = 2;
2786 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002787
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002788 for (i = 0; i < row_info->width; i++)
2789 {
2790 png_byte v;
2791 int j;
2792
2793 v = (png_byte)((*sp >> sshift) & 0x03);
2794 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002795 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002796 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2797 *dp |= (png_byte)(v << dshift);
2798 if (dshift == s_end)
2799 {
2800 dshift = s_start;
2801 dp--;
2802 }
2803 else
2804 dshift += s_inc;
2805 }
2806 if (sshift == s_end)
2807 {
2808 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002809 sp--;
2810 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002811 else
2812 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002813 }
2814 break;
2815 }
2816 case 4:
2817 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002818 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2819 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002820 int sshift, dshift;
2821 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002822 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002823 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002824
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002825#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002826 if (transformations & PNG_PACKSWAP)
2827 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002828 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2829 dshift = (int)(((final_width + 1) & 0x01) << 2);
2830 s_start = 4;
2831 s_end = 0;
2832 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002833 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002834 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002835#endif
2836 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002837 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2838 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2839 s_start = 0;
2840 s_end = 4;
2841 s_inc = 4;
2842 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002843
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002844 for (i = 0; i < row_info->width; i++)
2845 {
2846 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2847 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002848
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002849 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002850 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002851 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2852 *dp |= (png_byte)(v << dshift);
2853 if (dshift == s_end)
2854 {
2855 dshift = s_start;
2856 dp--;
2857 }
2858 else
2859 dshift += s_inc;
2860 }
2861 if (sshift == s_end)
2862 {
2863 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002864 sp--;
2865 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002866 else
2867 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002868 }
2869 break;
2870 }
2871 default:
2872 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002873 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002874 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2875 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002876 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002877
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002878 int jstop = png_pass_inc[pass];
2879 png_uint_32 i;
2880
2881 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002882 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002883 png_byte v[8];
2884 int j;
2885
2886 png_memcpy(v, sp, pixel_bytes);
2887 for (j = 0; j < jstop; j++)
2888 {
2889 png_memcpy(dp, v, pixel_bytes);
2890 dp -= pixel_bytes;
2891 }
2892 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002893 }
2894 break;
2895 }
2896 }
2897 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002898 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002899 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002900#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002901 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002902#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002903}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002904#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002905
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002906void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002907png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002908 png_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002909{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002910 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06002911 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002912 switch (filter)
2913 {
2914 case PNG_FILTER_VALUE_NONE:
2915 break;
2916 case PNG_FILTER_VALUE_SUB:
2917 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002918 png_uint_32 i;
2919 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002920 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002921 png_bytep rp = row + bpp;
2922 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002923
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002924 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002925 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002926 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2927 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002928 }
2929 break;
2930 }
2931 case PNG_FILTER_VALUE_UP:
2932 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002933 png_uint_32 i;
2934 png_uint_32 istop = row_info->rowbytes;
2935 png_bytep rp = row;
2936 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002937
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002938 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002939 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002940 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2941 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002942 }
2943 break;
2944 }
2945 case PNG_FILTER_VALUE_AVG:
2946 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002947 png_uint_32 i;
2948 png_bytep rp = row;
2949 png_bytep pp = prev_row;
2950 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002951 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002952 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002953
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002954 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002955 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002956 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002957 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002958 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002959 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002960
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002961 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002962 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002963 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06002964 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002965 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002966 }
2967 break;
2968 }
2969 case PNG_FILTER_VALUE_PAETH:
2970 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002971 png_uint_32 i;
2972 png_bytep rp = row;
2973 png_bytep pp = prev_row;
2974 png_bytep lp = row;
2975 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002976 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002977 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002978
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002979 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002980 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002981 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2982 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002983 }
2984
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002985 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002986 {
2987 int a, b, c, pa, pb, pc, p;
2988
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002989 a = *lp++;
2990 b = *pp++;
2991 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002992
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002993 p = b - c;
2994 pc = a - c;
2995
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002996#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002997 pa = abs(p);
2998 pb = abs(pc);
2999 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003000#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003001 pa = p < 0 ? -p : p;
3002 pb = pc < 0 ? -pc : pc;
3003 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003004#endif
3005
3006 /*
3007 if (pa <= pb && pa <= pc)
3008 p = a;
3009 else if (pb <= pc)
3010 p = b;
3011 else
3012 p = c;
3013 */
3014
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003015 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003016
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003017 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3018 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003019 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003020 break;
3021 }
3022 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003023 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003024 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003025 break;
3026 }
3027}
Guy Schalnat0d580581995-07-20 02:43:20 -05003028
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003029#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003030void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003031png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003032{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003033#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003034 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003035
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003036 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003037 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003038
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003039 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003040 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003041
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003042 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003043 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003044
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003045 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003046 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3047#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003048
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003049 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003050 png_ptr->row_number++;
3051 if (png_ptr->row_number < png_ptr->num_rows)
3052 return;
3053
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003054#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003055 if (png_ptr->interlaced)
3056 {
3057 png_ptr->row_number = 0;
Glenn Randers-Pehrsona31c74f2009-05-18 15:52:01 -05003058 png_memset(png_ptr->prev_row, 0,
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003059 png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003060 do
3061 {
3062 png_ptr->pass++;
3063 if (png_ptr->pass >= 7)
3064 break;
3065 png_ptr->iwidth = (png_ptr->width +
3066 png_pass_inc[png_ptr->pass] - 1 -
3067 png_pass_start[png_ptr->pass]) /
3068 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003069
Guy Schalnat0d580581995-07-20 02:43:20 -05003070 if (!(png_ptr->transformations & PNG_INTERLACE))
3071 {
3072 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003073 png_pass_yinc[png_ptr->pass] - 1 -
3074 png_pass_ystart[png_ptr->pass]) /
3075 png_pass_yinc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003076 if (!(png_ptr->num_rows))
3077 continue;
3078 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003079 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003080 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003081 } while (png_ptr->iwidth == 0);
3082
3083 if (png_ptr->pass < 7)
3084 return;
3085 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003086#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003087
Guy Schalnate5a37791996-06-05 15:50:50 -05003088 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003089 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003090 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003091 char extra;
3092 int ret;
3093
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003094 png_ptr->zstream.next_out = (Byte *)&extra;
3095 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003096 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003097 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003098 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003099 {
3100 while (!png_ptr->idat_size)
3101 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003102 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003103
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003104 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003105
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003106 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003107 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003108 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003109 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003110 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003111 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003112
3113 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003114 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3115 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05003116 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003117 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3118 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3119 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003120 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003121 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05003122 if (ret == Z_STREAM_END)
3123 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003124 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003125 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003126 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003127 png_ptr->mode |= PNG_AFTER_IDAT;
3128 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003129 break;
3130 }
3131 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003132 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003133 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003134
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003135 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003136 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003137 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003138 png_ptr->mode |= PNG_AFTER_IDAT;
3139 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3140 break;
3141 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003142
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003143 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003144 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003145 }
3146
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003147 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003148 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003149
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003150 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003151
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003152 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003153}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003154#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003155
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003156void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003157png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003158{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003159#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003160 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003161
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003162 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003163 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003164
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003165 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003166 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003167
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003168 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003169 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003170
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003171 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003172 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3173#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003174
Guy Schalnat0d580581995-07-20 02:43:20 -05003175 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003176 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003177
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003178 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003179 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003180 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003181#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003182 if (png_ptr->interlaced)
3183 {
3184 if (!(png_ptr->transformations & PNG_INTERLACE))
3185 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003186 png_pass_ystart[0]) / png_pass_yinc[0];
Guy Schalnat0d580581995-07-20 02:43:20 -05003187 else
3188 png_ptr->num_rows = png_ptr->height;
3189
3190 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003191 png_pass_inc[png_ptr->pass] - 1 -
3192 png_pass_start[png_ptr->pass]) /
3193 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003194 }
3195 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003196#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003197 {
3198 png_ptr->num_rows = png_ptr->height;
3199 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003200 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003201 max_pixel_depth = png_ptr->pixel_depth;
3202
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003203#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003204 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003205 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003206#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003207
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003208#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003209 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003210 {
3211 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3212 {
3213 if (png_ptr->num_trans)
3214 max_pixel_depth = 32;
3215 else
3216 max_pixel_depth = 24;
3217 }
3218 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3219 {
3220 if (max_pixel_depth < 8)
3221 max_pixel_depth = 8;
3222 if (png_ptr->num_trans)
3223 max_pixel_depth *= 2;
3224 }
3225 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3226 {
3227 if (png_ptr->num_trans)
3228 {
3229 max_pixel_depth *= 4;
3230 max_pixel_depth /= 3;
3231 }
3232 }
3233 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003234#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003235
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003236#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003237 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003238 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003239 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3240 max_pixel_depth = 32;
3241 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003242 {
3243 if (max_pixel_depth <= 8)
3244 max_pixel_depth = 16;
3245 else
3246 max_pixel_depth = 32;
3247 }
3248 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3249 {
3250 if (max_pixel_depth <= 32)
3251 max_pixel_depth = 32;
3252 else
3253 max_pixel_depth = 64;
3254 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003255 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003256#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003257
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003258#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003259 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3260 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003261 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003262#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003263 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003264#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003265#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003266 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003267#endif
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003268 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003269 {
3270 if (max_pixel_depth <= 16)
3271 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003272 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003273 max_pixel_depth = 64;
3274 }
3275 else
3276 {
3277 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003278 {
3279 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003280 max_pixel_depth = 32;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003281 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003282 max_pixel_depth = 24;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003283 }
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003284 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3285 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003286 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003287 max_pixel_depth = 48;
3288 }
3289 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003290#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003291
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003292#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3293defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003294 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003295 {
3296 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003297 png_ptr->user_transform_channels;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003298 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003299 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003300 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003301#endif
3302
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003303 /* Align the width on the next larger 8 pixels. Mainly used
3304 * for interlacing
3305 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003306 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003307 /* Calculate the maximum bytes needed, adding a byte and a pixel
3308 * for safety's sake
3309 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003310 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003311 1 + ((max_pixel_depth + 7) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05003312#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003313 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003314 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003315#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003316
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003317 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003318 {
3319 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003320 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003321 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3322 row_bytes + 48);
3323 else
3324 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3325 row_bytes + 48);
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003326 png_ptr->old_big_row_buf_size = row_bytes + 48;
3327
3328#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3329 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3330 * of padding before and after row_buf.
3331 */
3332 png_ptr->row_buf = png_ptr->big_row_buf + 32
3333 - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16);
3334 png_ptr->old_big_row_buf_size = row_bytes + 48;
3335#else
3336 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003337 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003338#endif
3339 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003340 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003341
3342#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003343 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003344 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003345#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003346 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003347 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003348
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003349 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003350 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003351 png_free(png_ptr, png_ptr->prev_row);
3352 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -06003353 png_ptr->rowbytes + 1));
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003354 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003355 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003356
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003357 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003358
Glenn Randers-Pehrson632a84e2010-03-09 22:28:33 -06003359 png_debug1(3, "width = %u,", png_ptr->width);
3360 png_debug1(3, "height = %u,", png_ptr->height);
3361 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3362 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
3363 png_debug1(3, "rowbytes = %u,", png_ptr->rowbytes);
3364 png_debug1(3, "irowbytes = %u",
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003365 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003366
Guy Schalnate5a37791996-06-05 15:50:50 -05003367 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003368}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003369#endif /* PNG_READ_SUPPORTED */