blob: e29fc6f3b6daa3b5e2d0ab336c50d64a3be3a38a [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-Pehrsone3f3c4e2010-02-07 18:08:50 -06004 * Last changed in libpng 1.4.1 [February 8, 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-Pehrsone3f3c4e2010-02-07 18:08:50 -060017#define PNG_INTERNAL
Glenn Randers-Pehrson03f9b022009-12-04 08:40:41 -060018#define PNG_NO_PEDANTIC_WARNINGS
Guy Schalnat0d580581995-07-20 02:43:20 -050019#include "png.h"
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -050020#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050021#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050022
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050023# define png_strtod(p,a,b) strtod(a,b)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060024png_uint_32 PNGAPI
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050025png_get_uint_31(png_structp png_ptr, png_bytep buf)
26{
27 png_uint_32 i = png_get_uint_32(buf);
28 if (i > PNG_UINT_31_MAX)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050029 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050030 return (i);
31}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050032#ifndef PNG_USE_READ_MACROS
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050033/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060034png_uint_32 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060035png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050036{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050037 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
Guy Schalnat0d580581995-07-20 02:43:20 -050038 ((png_uint_32)(*(buf + 1)) << 16) +
39 ((png_uint_32)(*(buf + 2)) << 8) +
40 (png_uint_32)(*(buf + 3));
41
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060042 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050043}
44
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050045/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050046 * 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 -050047 * assumed that the machine format for signed integers is the same.
48 */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060049png_int_32 PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -050050png_get_int_32(png_bytep buf)
51{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050052 png_int_32 i = ((png_int_32)(*buf) << 24) +
Andreas Dilger47a0c421997-05-16 02:46:07 -050053 ((png_int_32)(*(buf + 1)) << 16) +
54 ((png_int_32)(*(buf + 2)) << 8) +
55 (png_int_32)(*(buf + 3));
56
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060057 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050058}
Andreas Dilger47a0c421997-05-16 02:46:07 -050059
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050060/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060061png_uint_16 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060062png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050063{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050064 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060065 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050066
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060067 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050068}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050069#endif /* PNG_USE_READ_MACROS */
Guy Schalnat0d580581995-07-20 02:43:20 -050070
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050071/* Read the chunk header (length + type name).
72 * Put the type name into png_ptr->chunk_name, and return the length.
73 */
74png_uint_32 /* PRIVATE */
75png_read_chunk_header(png_structp png_ptr)
76{
77 png_byte buf[8];
78 png_uint_32 length;
79
80#ifdef PNG_IO_STATE_SUPPORTED
81 /* Inform the I/O callback that the chunk header is being read.
82 * PNG_IO_CHUNK_HDR requires a single I/O call.
83 */
84 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
85#endif
86
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050087 /* Read the length and the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050088 png_read_data(png_ptr, buf, 8);
89 length = png_get_uint_31(png_ptr, buf);
90
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050091 /* Put the chunk name into png_ptr->chunk_name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050092 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
93
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050094 png_debug2(0, "Reading %s chunk, length = %lu",
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050095 png_ptr->chunk_name, length);
96
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050097 /* Reset the crc and run it over the chunk name */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050098 png_reset_crc(png_ptr);
99 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
100
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500101 /* Check to see if chunk name is valid */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500102 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
103
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500104#ifdef PNG_IO_STATE_SUPPORTED
105 /* Inform the I/O callback that chunk data will (possibly) be read.
106 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
107 */
108 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
109#endif
110
111 return length;
112}
113
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500114/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500115void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500116png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500117{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500118 if (png_ptr == NULL)
119 return;
Guy Schalnat6d764711995-12-19 03:22:19 -0600120 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500121 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500122}
123
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600124/* Optionally skip data and then check the CRC. Depending on whether we
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500125 * are reading a ancillary or critical chunk, and how the program has set
126 * things up, we may calculate the CRC on the data and print a message.
127 * Returns '1' if there was a CRC error, '0' otherwise.
128 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500129int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600130png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500131{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500132 png_size_t i;
133 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500134
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500135 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600136 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500137 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500138 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500139 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500140 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500141 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500142 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600143
Andreas Dilger47a0c421997-05-16 02:46:07 -0500144 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600145 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500146 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500147 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500148 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600149 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600150 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600151 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600152 }
153 else
154 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500155 png_chunk_benign_error(png_ptr, "CRC error");
156 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600157 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600158 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600159 }
160
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600161 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500162}
163
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600164/* 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 -0500165 * the data it has read thus far.
166 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500167int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600168png_crc_error(png_structp png_ptr)
169{
170 png_byte crc_bytes[4];
171 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500172 int need_crc = 1;
173
174 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
175 {
176 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
177 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
178 need_crc = 0;
179 }
180 else /* critical */
181 {
182 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
183 need_crc = 0;
184 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600185
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500186#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500187 /* Inform the I/O callback that the chunk CRC is being read */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500188 /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */
189 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
190#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500191
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600192 png_read_data(png_ptr, crc_bytes, 4);
193
Andreas Dilger47a0c421997-05-16 02:46:07 -0500194 if (need_crc)
195 {
196 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600197 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500198 }
199 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600200 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600201}
202
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600203#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500204 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600205png_size_t
206png_measure_decompressed_chunk(png_structp png_ptr, int comp_type,
207 png_size_t chunklength, png_size_t prefix_size)
208{
209 png_charp text;
210 png_charp test = "X";
211 png_size_t text_size = 0;
212
213 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
214 {
215 int ret = Z_OK;
216
217 png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size);
218 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
219 png_ptr->zstream.next_out = png_ptr->zbuf;
220 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
221
222 text = NULL;
223
224 while (png_ptr->zstream.avail_in)
225 {
226 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
227 if (ret != Z_OK && ret != Z_STREAM_END)
228 {
229 inflateReset(&png_ptr->zstream);
230 png_ptr->zstream.avail_in = 0;
231 break;
232 }
233 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
234 {
235 if (text == NULL) /* Initialize the decompression buffer */
236 {
237 text_size = prefix_size +
238 png_ptr->zbuf_size - png_ptr->zstream.avail_out;
239
240 text=test;
241 }
242 else /* Enlarge the decompression buffer */
243 {
244 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
245#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
246 if (png_ptr->user_chunk_malloc_max &&
247 (text_size >= png_ptr->user_chunk_malloc_max - 1))
248#else
249 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
250 text_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
251#endif
252 return 0;
253 }
254 }
255 if (ret == Z_STREAM_END)
256 break;
257
258 else
259 {
260 png_ptr->zstream.next_out = png_ptr->zbuf;
261 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
262 }
263 }
264
265 inflateReset(&png_ptr->zstream);
266 png_ptr->zstream.avail_in = 0;
267 }
268 return text_size;
269}
270
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600271/*
272 * Decompress trailing data in a chunk. The assumption is that chunkdata
273 * points at an allocated area holding the contents of a chunk with a
274 * trailing compressed part. What we get back is an allocated area
275 * holding the original prefix part and an uncompressed version of the
276 * trailing part (the malloc area passed in is freed).
277 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500278void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500279png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600280 png_size_t chunklength,
281 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600282{
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -0500283 static PNG_CONST char msg[] = "Error decoding compressed chunk";
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500284 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600285 png_size_t text_size;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600286 png_size_t expanded_size;
287
288 expanded_size= png_measure_decompressed_chunk(png_ptr, comp_type,
289 chunklength, prefix_size);
290 if (expanded_size == 0)
291 {
292 *newlength=0;
293 return;
294 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600295
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600296 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600297 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500298 int ret = Z_OK;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600299 png_size_t buffer_size;
300
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500301 png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600302 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
303 png_ptr->zstream.next_out = png_ptr->zbuf;
304 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
305
306 text_size = 0;
307 text = NULL;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600308 buffer_size = 0;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600309
310 while (png_ptr->zstream.avail_in)
311 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500312 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600313 if (ret != Z_OK && ret != Z_STREAM_END)
314 {
315 if (png_ptr->zstream.msg != NULL)
316 png_warning(png_ptr, png_ptr->zstream.msg);
317 else
318 png_warning(png_ptr, msg);
319 inflateReset(&png_ptr->zstream);
320 png_ptr->zstream.avail_in = 0;
321
322 if (text == NULL)
323 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500324 text_size = prefix_size + png_sizeof(msg) + 1;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500325 text = (png_charp)png_malloc_warn(png_ptr, text_size);
326 if (text == NULL)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600327 {
328 png_error(png_ptr,
329 "Not enough memory to decompress chunk");
330 text_size = 0;
331 break;
332 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500333 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600334 }
335
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500336 text[text_size - 1] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600337
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500338 /* Copy what we can of the error message into the text chunk */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500339 text_size = (png_size_t)(chunklength -
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600340 (text - png_ptr->chunkdata) - 1);
341
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500342 if (text_size > png_sizeof(msg))
343 text_size = png_sizeof(msg);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600344
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500345 png_memcpy(text + prefix_size, msg, text_size);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600346 buffer_size = text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600347 break;
348 }
349 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
350 {
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600351 if (text == NULL) /* Initialize the decompression buffer */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600352 {
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600353 text_size = expanded_size;
354
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500355 text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
356 if (text == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500357 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500358 png_error(png_ptr,
359 "Not enough memory to decompress chunk");
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600360 text_size = 0;
361 break;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500362 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500363 png_memcpy(text + prefix_size, png_ptr->zbuf,
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500364 text_size - prefix_size);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500365 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500366 *(text + text_size) = 0x00;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600367 buffer_size = text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600368 }
369 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600370 if (ret == Z_STREAM_END)
371 break;
372
373 else
374 {
375 png_ptr->zstream.next_out = png_ptr->zbuf;
376 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
377 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600378 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600379
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500380 if (ret != Z_STREAM_END)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500381 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500382#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrsonf46918d2006-06-02 05:31:20 -0500383 char umsg[52];
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500384
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500385 if (ret == Z_BUF_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500386 png_snprintf(umsg, 52,
387 "Buffer error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500388 png_ptr->chunk_name);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500389
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500390 else if (ret == Z_DATA_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500391 png_snprintf(umsg, 52,
392 "Data error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500393 png_ptr->chunk_name);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500394
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500395 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500396 png_snprintf(umsg, 52,
397 "Incomplete compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500398 png_ptr->chunk_name);
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500399
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500400 png_warning(png_ptr, umsg);
401#else
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500402 png_warning(png_ptr,
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500403 "Incomplete compressed datastream in chunk other than IDAT");
404#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500405 text_size = prefix_size;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600406 if (text == NULL)
407 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500408 text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
409 if (text == NULL)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600410 {
411 png_free(png_ptr, png_ptr->chunkdata);
412 png_ptr->chunkdata = NULL;
413 png_error(png_ptr, "Not enough memory for text");
414 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500415 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600416 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500417 *(text + text_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500418 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600419
420 inflateReset(&png_ptr->zstream);
421 png_ptr->zstream.avail_in = 0;
422
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500423 png_free(png_ptr, png_ptr->chunkdata);
424 png_ptr->chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600425 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600426 }
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600427 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600428 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500429#ifdef PNG_STDIO_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600430 char umsg[50];
431
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500432 png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600433 png_warning(png_ptr, umsg);
434#else
435 png_warning(png_ptr, "Unknown zTXt compression type");
436#endif
437
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500438 *(png_ptr->chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500439 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600440 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600441}
442#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600443
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500444/* Read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500445void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600446png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500447{
448 png_byte buf[13];
449 png_uint_32 width, height;
450 int bit_depth, color_type, compression_type, filter_type;
451 int interlace_type;
452
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500453 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500454
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600455 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500456 png_error(png_ptr, "Out of place IHDR");
457
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500458 /* Check the length */
Guy Schalnat0d580581995-07-20 02:43:20 -0500459 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600460 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500461
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600462 png_ptr->mode |= PNG_HAVE_IHDR;
463
Guy Schalnat0d580581995-07-20 02:43:20 -0500464 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600465 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500466
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500467 width = png_get_uint_31(png_ptr, buf);
468 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500469 bit_depth = buf[8];
470 color_type = buf[9];
471 compression_type = buf[10];
472 filter_type = buf[11];
473 interlace_type = buf[12];
474
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500475 /* Set internal variables */
Guy Schalnat0d580581995-07-20 02:43:20 -0500476 png_ptr->width = width;
477 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600478 png_ptr->bit_depth = (png_byte)bit_depth;
479 png_ptr->interlaced = (png_byte)interlace_type;
480 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500481#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600482 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500483#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500484 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500485
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500486 /* Find number of channels */
Guy Schalnat0d580581995-07-20 02:43:20 -0500487 switch (png_ptr->color_type)
488 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500489 case PNG_COLOR_TYPE_GRAY:
490 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500491 png_ptr->channels = 1;
492 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500493
Andreas Dilger47a0c421997-05-16 02:46:07 -0500494 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500495 png_ptr->channels = 3;
496 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500497
Andreas Dilger47a0c421997-05-16 02:46:07 -0500498 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500499 png_ptr->channels = 2;
500 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500501
Andreas Dilger47a0c421997-05-16 02:46:07 -0500502 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500503 png_ptr->channels = 4;
504 break;
505 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600506
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500507 /* Set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600508 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600509 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500510 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500511 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
512 png_debug1(3, "channels = %d", png_ptr->channels);
513 png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500514 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
515 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500516}
517
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500518/* Read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500519void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600520png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500521{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600522 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600523 int num, i;
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500524#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500525 png_colorp pal_ptr;
526#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500527
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500528 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500529
Guy Schalnate5a37791996-06-05 15:50:50 -0500530 if (!(png_ptr->mode & PNG_HAVE_IHDR))
531 png_error(png_ptr, "Missing IHDR before PLTE");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500532
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600533 else if (png_ptr->mode & PNG_HAVE_IDAT)
534 {
535 png_warning(png_ptr, "Invalid PLTE after IDAT");
536 png_crc_finish(png_ptr, length);
537 return;
538 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500539
Guy Schalnate5a37791996-06-05 15:50:50 -0500540 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600541 png_error(png_ptr, "Duplicate PLTE chunk");
542
543 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500544
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500545 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
546 {
547 png_warning(png_ptr,
548 "Ignoring PLTE chunk in grayscale PNG");
549 png_crc_finish(png_ptr, length);
550 return;
551 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500552#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500553 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
554 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600555 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500556 return;
557 }
558#endif
559
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600560 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500561 {
562 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
563 {
564 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600565 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500566 return;
567 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500568
Guy Schalnate5a37791996-06-05 15:50:50 -0500569 else
570 {
571 png_error(png_ptr, "Invalid palette chunk");
572 }
573 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500574
575 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500576
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500577#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500578 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
579 {
580 png_byte buf[3];
581
582 png_crc_read(png_ptr, buf, 3);
583 pal_ptr->red = buf[0];
584 pal_ptr->green = buf[1];
585 pal_ptr->blue = buf[2];
586 }
587#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600588 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500589 {
590 png_byte buf[3];
591
592 png_crc_read(png_ptr, buf, 3);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500593 /* Don't depend upon png_color being any order */
Guy Schalnat0d580581995-07-20 02:43:20 -0500594 palette[i].red = buf[0];
595 palette[i].green = buf[1];
596 palette[i].blue = buf[2];
597 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500598#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600599
600 /* 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 -0500601 * whatever the normal CRC configuration tells us. However, if we
602 * have an RGB image, the PLTE can be considered ancillary, so
603 * we will act as though it is.
604 */
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500605#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600606 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600607#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600608 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500609 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600610 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500611#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600612 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
613 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600614 /* If we don't want to use the data from an ancillary chunk,
615 we have two options: an error abort, or a warning and we
616 ignore the data in this chunk (which should be OK, since
617 it's considered ancillary for a RGB or RGBA image). */
618 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
619 {
620 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
621 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500622 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600623 }
624 else
625 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600626 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600627 return;
628 }
629 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500630 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600631 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
632 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600633 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600634 }
635 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600636#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500637
Andreas Dilger47a0c421997-05-16 02:46:07 -0500638 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500639
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500640#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500641 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
642 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600643 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500644 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500645 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500646 {
647 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500648 png_ptr->num_trans = (png_uint_16)num;
649 }
650 if (info_ptr->num_trans > (png_uint_16)num)
651 {
652 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
653 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500654 }
655 }
656 }
657#endif
658
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600659}
Guy Schalnate5a37791996-06-05 15:50:50 -0500660
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500661void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600662png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
663{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500664 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500665
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600666 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
667 {
668 png_error(png_ptr, "No image in file");
669 }
670
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600671 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600672
673 if (length != 0)
674 {
675 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600676 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500677 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500678
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500679 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500680}
681
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500682#ifdef PNG_READ_gAMA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500683void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600684png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500685{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600686 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600687#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500688 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600689#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500690 png_byte buf[4];
691
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500692 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500693
Guy Schalnate5a37791996-06-05 15:50:50 -0500694 if (!(png_ptr->mode & PNG_HAVE_IHDR))
695 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600696 else if (png_ptr->mode & PNG_HAVE_IDAT)
697 {
698 png_warning(png_ptr, "Invalid gAMA after IDAT");
699 png_crc_finish(png_ptr, length);
700 return;
701 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500702 else if (png_ptr->mode & PNG_HAVE_PLTE)
703 /* Should be an error, but we can cope with it */
704 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600705
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500706 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500707#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600708 && !(info_ptr->valid & PNG_INFO_sRGB)
709#endif
710 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600711 {
712 png_warning(png_ptr, "Duplicate gAMA chunk");
713 png_crc_finish(png_ptr, length);
714 return;
715 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500716
Guy Schalnat0d580581995-07-20 02:43:20 -0500717 if (length != 4)
718 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600719 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600720 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500721 return;
722 }
723
724 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600725 if (png_crc_finish(png_ptr, 0))
726 return;
727
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600728 igamma = (png_fixed_point)png_get_uint_32(buf);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500729 /* Check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500730 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500731 {
732 png_warning(png_ptr,
733 "Ignoring gAMA chunk with gamma=0");
734 return;
735 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500736
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500737#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600738 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500739 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600740 {
741 png_warning(png_ptr,
742 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500743#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -0600744 fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600745#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600746 return;
747 }
748#endif /* PNG_READ_sRGB_SUPPORTED */
749
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600750#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600751 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600752# ifdef PNG_READ_GAMMA_SUPPORTED
753 png_ptr->gamma = file_gamma;
754# endif
755 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600756#endif
757#ifdef PNG_FIXED_POINT_SUPPORTED
758 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
759#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500760}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500761#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500762
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500763#ifdef PNG_READ_sBIT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500764void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600765png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500766{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500767 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600768 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600769
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500770 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500771
Guy Schalnat69b14481996-01-10 02:56:49 -0600772 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500773
Guy Schalnate5a37791996-06-05 15:50:50 -0500774 if (!(png_ptr->mode & PNG_HAVE_IHDR))
775 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600776 else if (png_ptr->mode & PNG_HAVE_IDAT)
777 {
778 png_warning(png_ptr, "Invalid sBIT after IDAT");
779 png_crc_finish(png_ptr, length);
780 return;
781 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500782 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600783 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500784 /* Should be an error, but we can cope with it */
785 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600786 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500787 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600788 {
789 png_warning(png_ptr, "Duplicate sBIT chunk");
790 png_crc_finish(png_ptr, length);
791 return;
792 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500793
Guy Schalnat0d580581995-07-20 02:43:20 -0500794 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600795 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500796 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500797 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500798
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500799 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500800 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600801 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600802 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600803 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500804 }
805
Andreas Dilger47a0c421997-05-16 02:46:07 -0500806 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600807 if (png_crc_finish(png_ptr, 0))
808 return;
809
Guy Schalnat0d580581995-07-20 02:43:20 -0500810 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
811 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600812 png_ptr->sig_bit.red = buf[0];
813 png_ptr->sig_bit.green = buf[1];
814 png_ptr->sig_bit.blue = buf[2];
815 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500816 }
817 else
818 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600819 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600820 png_ptr->sig_bit.red = buf[0];
821 png_ptr->sig_bit.green = buf[0];
822 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600823 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500824 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500825 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500826}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500827#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500828
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500829#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500830void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600831png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500832{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500833 png_byte buf[32];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600834#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500835 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 -0600836#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600837 png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600838 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500839
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600840 png_uint_32 uint_x, uint_y;
841
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500842 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500843
Guy Schalnate5a37791996-06-05 15:50:50 -0500844 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600845 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600846 else if (png_ptr->mode & PNG_HAVE_IDAT)
847 {
848 png_warning(png_ptr, "Invalid cHRM after IDAT");
849 png_crc_finish(png_ptr, length);
850 return;
851 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500852 else if (png_ptr->mode & PNG_HAVE_PLTE)
853 /* Should be an error, but we can cope with it */
854 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600855
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500856 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500857#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600858 && !(info_ptr->valid & PNG_INFO_sRGB)
859#endif
860 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600861 {
862 png_warning(png_ptr, "Duplicate cHRM chunk");
863 png_crc_finish(png_ptr, length);
864 return;
865 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500866
Guy Schalnat0d580581995-07-20 02:43:20 -0500867 if (length != 32)
868 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600869 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600870 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600871 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500872 }
873
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500874 png_crc_read(png_ptr, buf, 32);
875 if (png_crc_finish(png_ptr, 0))
876 return;
877
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600878 uint_x = png_get_uint_32(buf);
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500879 uint_y = png_get_uint_32(buf + 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600880 int_x_white = (png_fixed_point)uint_x;
881 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500882
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500883 uint_x = png_get_uint_32(buf + 8);
884 uint_y = png_get_uint_32(buf + 12);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600885 int_x_red = (png_fixed_point)uint_x;
886 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500887
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500888 uint_x = png_get_uint_32(buf + 16);
889 uint_y = png_get_uint_32(buf + 20);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600890 int_x_green = (png_fixed_point)uint_x;
891 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500892
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500893 uint_x = png_get_uint_32(buf + 24);
894 uint_y = png_get_uint_32(buf + 28);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600895 int_x_blue = (png_fixed_point)uint_x;
896 int_y_blue = (png_fixed_point)uint_y;
897
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600898#ifdef PNG_FLOATING_POINT_SUPPORTED
899 white_x = (float)int_x_white / (float)100000.0;
900 white_y = (float)int_y_white / (float)100000.0;
901 red_x = (float)int_x_red / (float)100000.0;
902 red_y = (float)int_y_red / (float)100000.0;
903 green_x = (float)int_x_green / (float)100000.0;
904 green_y = (float)int_y_green / (float)100000.0;
905 blue_x = (float)int_x_blue / (float)100000.0;
906 blue_y = (float)int_y_blue / (float)100000.0;
907#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600908
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500909#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500910 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600911 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500912 if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
913 PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
914 PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
915 PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
916 PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
917 PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
918 PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
919 PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600920 {
921 png_warning(png_ptr,
922 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500923#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600924#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500925 fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600926 white_x, white_y, red_x, red_y);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500927 fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600928 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600929#else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500930 fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600931 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500932 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600933 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600934#endif
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500935#endif /* PNG_CONSOLE_IO_SUPPORTED */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600936 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600937 return;
938 }
939#endif /* PNG_READ_sRGB_SUPPORTED */
940
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600941#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500942 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600943 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600944#endif
945#ifdef PNG_FIXED_POINT_SUPPORTED
946 png_set_cHRM_fixed(png_ptr, info_ptr,
947 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
948 int_y_green, int_x_blue, int_y_blue);
949#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500950}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500951#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500952
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500953#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500954void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600955png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
956{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600957 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600958 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600959
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500960 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600961
962 if (!(png_ptr->mode & PNG_HAVE_IHDR))
963 png_error(png_ptr, "Missing IHDR before sRGB");
964 else if (png_ptr->mode & PNG_HAVE_IDAT)
965 {
966 png_warning(png_ptr, "Invalid sRGB after IDAT");
967 png_crc_finish(png_ptr, length);
968 return;
969 }
970 else if (png_ptr->mode & PNG_HAVE_PLTE)
971 /* Should be an error, but we can cope with it */
972 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600973
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500974 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600975 {
976 png_warning(png_ptr, "Duplicate sRGB chunk");
977 png_crc_finish(png_ptr, length);
978 return;
979 }
980
981 if (length != 1)
982 {
983 png_warning(png_ptr, "Incorrect sRGB chunk length");
984 png_crc_finish(png_ptr, length);
985 return;
986 }
987
988 png_crc_read(png_ptr, buf, 1);
989 if (png_crc_finish(png_ptr, 0))
990 return;
991
992 intent = buf[0];
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500993 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600994 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600995 {
996 png_warning(png_ptr, "Unknown sRGB intent");
997 return;
998 }
999
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001000#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001001 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001002 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001003 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001004#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001005 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001006#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001007# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001008 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001009# endif
1010#endif
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -05001011 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001012 {
1013 png_warning(png_ptr,
1014 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001015#ifdef PNG_CONSOLE_IO_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001016# ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001017 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
1018 (int)png_ptr->int_gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001019# else
1020# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001021 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001022# endif
1023# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001024#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001025 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001026 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001027#endif /* PNG_READ_gAMA_SUPPORTED */
1028
1029#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001030#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001031 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -05001032 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
1033 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
1034 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
1035 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
1036 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
1037 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
1038 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
1039 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001040 {
1041 png_warning(png_ptr,
1042 "Ignoring incorrect cHRM value when sRGB is also present");
1043 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001044#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001045#endif /* PNG_READ_cHRM_SUPPORTED */
1046
1047 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1048}
1049#endif /* PNG_READ_sRGB_SUPPORTED */
1050
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001051#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001052void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001053png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1054/* Note: this does not properly handle chunks that are > 64K under DOS */
1055{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001056 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001057 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001058 png_charp profile;
1059 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001060 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001061 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001062
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001063 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001064
1065 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1066 png_error(png_ptr, "Missing IHDR before iCCP");
1067 else if (png_ptr->mode & PNG_HAVE_IDAT)
1068 {
1069 png_warning(png_ptr, "Invalid iCCP after IDAT");
1070 png_crc_finish(png_ptr, length);
1071 return;
1072 }
1073 else if (png_ptr->mode & PNG_HAVE_PLTE)
1074 /* Should be an error, but we can cope with it */
1075 png_warning(png_ptr, "Out of place iCCP chunk");
1076
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001077 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001078 {
1079 png_warning(png_ptr, "Duplicate iCCP chunk");
1080 png_crc_finish(png_ptr, length);
1081 return;
1082 }
1083
1084#ifdef PNG_MAX_MALLOC_64K
1085 if (length > (png_uint_32)65535L)
1086 {
1087 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1088 skip = length - (png_uint_32)65535L;
1089 length = (png_uint_32)65535L;
1090 }
1091#endif
1092
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001093 png_free(png_ptr, png_ptr->chunkdata);
1094 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001095 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001096 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001097
1098 if (png_crc_finish(png_ptr, skip))
1099 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001100 png_free(png_ptr, png_ptr->chunkdata);
1101 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001102 return;
1103 }
1104
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001105 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001106
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001107 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001108 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001109
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001110 ++profile;
1111
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001112 /* There should be at least one zero (the compression type byte)
1113 * following the separator, and we should be on it
1114 */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001115 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001116 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001117 png_free(png_ptr, png_ptr->chunkdata);
1118 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001119 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001120 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001121 }
1122
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001123 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001124 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001125 if (compression_type)
1126 {
1127 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001128 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001129 wrote nonzero) */
1130 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001131
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001132 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001133 png_decompress_chunk(png_ptr, compression_type,
1134 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001135
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001136 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001137
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001138 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001139 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001140 png_free(png_ptr, png_ptr->chunkdata);
1141 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001142 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1143 return;
1144 }
1145
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001146 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001147 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -05001148 profile_size = ((*(pC ))<<24) |
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001149 ((*(pC + 1))<<16) |
1150 ((*(pC + 2))<< 8) |
1151 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001152
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001153 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001154 profile_length = profile_size;
1155
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001156 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001157 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001158 png_free(png_ptr, png_ptr->chunkdata);
1159 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001160 png_warning(png_ptr, "Ignoring truncated iCCP profile");
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001161 return;
1162 }
1163
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001164 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
1165 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
1166 png_free(png_ptr, png_ptr->chunkdata);
1167 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001168}
1169#endif /* PNG_READ_iCCP_SUPPORTED */
1170
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001171#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001172void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001173png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1174/* Note: this does not properly handle chunks that are > 64K under DOS */
1175{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001176 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001177 png_sPLT_t new_palette;
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001178#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001179 png_sPLT_entryp pp;
1180#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001181 int data_length, entry_size, i;
1182 png_uint_32 skip = 0;
1183 png_size_t slength;
1184
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001185 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001186
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001187#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001188
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001189 if (png_ptr->user_chunk_cache_max != 0)
1190 {
1191 if (png_ptr->user_chunk_cache_max == 1)
1192 {
1193 png_crc_finish(png_ptr, length);
1194 return;
1195 }
1196 if (--png_ptr->user_chunk_cache_max == 1)
1197 {
1198 png_warning(png_ptr, "No space in chunk cache for sPLT");
1199 png_crc_finish(png_ptr, length);
1200 return;
1201 }
1202 }
1203#endif
1204
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001205 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1206 png_error(png_ptr, "Missing IHDR before sPLT");
1207 else if (png_ptr->mode & PNG_HAVE_IDAT)
1208 {
1209 png_warning(png_ptr, "Invalid sPLT after IDAT");
1210 png_crc_finish(png_ptr, length);
1211 return;
1212 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001213
1214#ifdef PNG_MAX_MALLOC_64K
1215 if (length > (png_uint_32)65535L)
1216 {
1217 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1218 skip = length - (png_uint_32)65535L;
1219 length = (png_uint_32)65535L;
1220 }
1221#endif
1222
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001223 png_free(png_ptr, png_ptr->chunkdata);
1224 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001225 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001226 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001227
1228 if (png_crc_finish(png_ptr, skip))
1229 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001230 png_free(png_ptr, png_ptr->chunkdata);
1231 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001232 return;
1233 }
1234
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001235 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001236
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001237 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1238 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001239 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001240 ++entry_start;
1241
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001242 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001243 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001244 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001245 png_free(png_ptr, png_ptr->chunkdata);
1246 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001247 png_warning(png_ptr, "malformed sPLT chunk");
1248 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001249 }
1250
1251 new_palette.depth = *entry_start++;
1252 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001253 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001254
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001255 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001256 if (data_length % entry_size)
1257 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001258 png_free(png_ptr, png_ptr->chunkdata);
1259 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001260 png_warning(png_ptr, "sPLT chunk has bad length");
1261 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001262 }
1263
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001264 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001265 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001266 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001267 {
1268 png_warning(png_ptr, "sPLT chunk too long");
1269 return;
1270 }
1271 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001272 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001273 if (new_palette.entries == NULL)
1274 {
1275 png_warning(png_ptr, "sPLT chunk requires too much memory");
1276 return;
1277 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001278
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001279#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001280 for (i = 0; i < new_palette.nentries; i++)
1281 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001282 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001283
1284 if (new_palette.depth == 8)
1285 {
1286 pp->red = *entry_start++;
1287 pp->green = *entry_start++;
1288 pp->blue = *entry_start++;
1289 pp->alpha = *entry_start++;
1290 }
1291 else
1292 {
1293 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1294 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1295 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1296 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1297 }
1298 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1299 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001300#else
1301 pp = new_palette.entries;
1302 for (i = 0; i < new_palette.nentries; i++)
1303 {
1304
1305 if (new_palette.depth == 8)
1306 {
1307 pp[i].red = *entry_start++;
1308 pp[i].green = *entry_start++;
1309 pp[i].blue = *entry_start++;
1310 pp[i].alpha = *entry_start++;
1311 }
1312 else
1313 {
1314 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1315 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1316 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1317 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1318 }
1319 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1320 }
1321#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001322
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001323 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001324 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001325
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001326 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001327
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001328 png_free(png_ptr, png_ptr->chunkdata);
1329 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001330 png_free(png_ptr, new_palette.entries);
1331}
1332#endif /* PNG_READ_sPLT_SUPPORTED */
1333
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001334#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001335void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001336png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001337{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001338 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001339
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001340 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001341
Guy Schalnate5a37791996-06-05 15:50:50 -05001342 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1343 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001344 else if (png_ptr->mode & PNG_HAVE_IDAT)
1345 {
1346 png_warning(png_ptr, "Invalid tRNS after IDAT");
1347 png_crc_finish(png_ptr, length);
1348 return;
1349 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001350 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001351 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001352 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001353 png_crc_finish(png_ptr, length);
1354 return;
1355 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001356
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001357 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001358 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001359 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001360
1361 if (length != 2)
1362 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001363 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001364 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001365 return;
1366 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001367
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001368 png_crc_read(png_ptr, buf, 2);
1369 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001370 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001371 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001372 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1373 {
1374 png_byte buf[6];
1375
1376 if (length != 6)
1377 {
1378 png_warning(png_ptr, "Incorrect tRNS chunk length");
1379 png_crc_finish(png_ptr, length);
1380 return;
1381 }
1382 png_crc_read(png_ptr, buf, (png_size_t)length);
1383 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001384 png_ptr->trans_color.red = png_get_uint_16(buf);
1385 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1386 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001387 }
1388 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1389 {
1390 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1391 {
1392 /* Should be an error, but we can cope with it. */
1393 png_warning(png_ptr, "Missing PLTE before tRNS");
1394 }
1395 if (length > (png_uint_32)png_ptr->num_palette ||
1396 length > PNG_MAX_PALETTE_LENGTH)
1397 {
1398 png_warning(png_ptr, "Incorrect tRNS chunk length");
1399 png_crc_finish(png_ptr, length);
1400 return;
1401 }
1402 if (length == 0)
1403 {
1404 png_warning(png_ptr, "Zero length tRNS chunk");
1405 png_crc_finish(png_ptr, length);
1406 return;
1407 }
1408 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1409 png_ptr->num_trans = (png_uint_16)length;
1410 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001411 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001412 {
1413 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001414 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001415 return;
1416 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001417
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001418 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001419 {
1420 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001421 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001422 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001423
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001424 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001425 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001426}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001427#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001428
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001429#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001430void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001431png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001432{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001433 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001434 png_byte buf[6];
1435
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001436 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001437
Guy Schalnate5a37791996-06-05 15:50:50 -05001438 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1439 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001440 else if (png_ptr->mode & PNG_HAVE_IDAT)
1441 {
1442 png_warning(png_ptr, "Invalid bKGD after IDAT");
1443 png_crc_finish(png_ptr, length);
1444 return;
1445 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001446 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1447 !(png_ptr->mode & PNG_HAVE_PLTE))
1448 {
1449 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001450 png_crc_finish(png_ptr, length);
1451 return;
1452 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001453 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001454 {
1455 png_warning(png_ptr, "Duplicate bKGD chunk");
1456 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001457 return;
1458 }
1459
Guy Schalnat0d580581995-07-20 02:43:20 -05001460 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1461 truelen = 1;
1462 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1463 truelen = 6;
1464 else
1465 truelen = 2;
1466
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001467 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001468 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001469 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001470 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001471 return;
1472 }
1473
Andreas Dilger47a0c421997-05-16 02:46:07 -05001474 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001475 if (png_crc_finish(png_ptr, 0))
1476 return;
1477
Guy Schalnate5a37791996-06-05 15:50:50 -05001478 /* We convert the index value into RGB components so that we can allow
1479 * arbitrary RGB values for background when we have transparency, and
1480 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001481 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001482 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001483 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001484 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001485 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001486 {
Glenn Randers-Pehrson79134c62009-02-14 10:32:18 -06001487 if (buf[0] >= info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001488 {
1489 png_warning(png_ptr, "Incorrect bKGD chunk index value");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001490 return;
1491 }
1492 png_ptr->background.red =
1493 (png_uint_16)png_ptr->palette[buf[0]].red;
1494 png_ptr->background.green =
1495 (png_uint_16)png_ptr->palette[buf[0]].green;
1496 png_ptr->background.blue =
1497 (png_uint_16)png_ptr->palette[buf[0]].blue;
1498 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001499 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001500 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001501 {
1502 png_ptr->background.red =
1503 png_ptr->background.green =
1504 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001505 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001506 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001507 else
1508 {
1509 png_ptr->background.red = png_get_uint_16(buf);
1510 png_ptr->background.green = png_get_uint_16(buf + 2);
1511 png_ptr->background.blue = png_get_uint_16(buf + 4);
1512 }
1513
Andreas Dilger47a0c421997-05-16 02:46:07 -05001514 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001515}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001516#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001517
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001518#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001519void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001520png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001521{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001522 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001523 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001524
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001525 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001526
Guy Schalnate5a37791996-06-05 15:50:50 -05001527 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1528 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001529 else if (png_ptr->mode & PNG_HAVE_IDAT)
1530 {
1531 png_warning(png_ptr, "Invalid hIST after IDAT");
1532 png_crc_finish(png_ptr, length);
1533 return;
1534 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001535 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1536 {
1537 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001538 png_crc_finish(png_ptr, length);
1539 return;
1540 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001541 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001542 {
1543 png_warning(png_ptr, "Duplicate hIST chunk");
1544 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001545 return;
1546 }
1547
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001548 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001549 if (num != (unsigned int) png_ptr->num_palette || num >
1550 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001551 {
1552 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001553 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001554 return;
1555 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001556
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001557 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001558 {
1559 png_byte buf[2];
1560
1561 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001562 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001563 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001564
1565 if (png_crc_finish(png_ptr, 0))
1566 return;
1567
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001568 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001569}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001570#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001571
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001572#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001573void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001574png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001575{
1576 png_byte buf[9];
1577 png_uint_32 res_x, res_y;
1578 int unit_type;
1579
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001580 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001581
Guy Schalnate5a37791996-06-05 15:50:50 -05001582 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001583 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001584 else if (png_ptr->mode & PNG_HAVE_IDAT)
1585 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001586 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001587 png_crc_finish(png_ptr, length);
1588 return;
1589 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001590 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001591 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001592 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001593 png_crc_finish(png_ptr, length);
1594 return;
1595 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001596
Guy Schalnat0d580581995-07-20 02:43:20 -05001597 if (length != 9)
1598 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001599 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001600 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001601 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001602 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001603
1604 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001605 if (png_crc_finish(png_ptr, 0))
1606 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001607
1608 res_x = png_get_uint_32(buf);
1609 res_y = png_get_uint_32(buf + 4);
1610 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001611 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001612}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001613#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001614
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001615#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001616void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001617png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001618{
1619 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001620 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001621 int unit_type;
1622
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001623 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001624
Guy Schalnate5a37791996-06-05 15:50:50 -05001625 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1626 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001627 else if (png_ptr->mode & PNG_HAVE_IDAT)
1628 {
1629 png_warning(png_ptr, "Invalid oFFs after IDAT");
1630 png_crc_finish(png_ptr, length);
1631 return;
1632 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001633 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001634 {
1635 png_warning(png_ptr, "Duplicate oFFs chunk");
1636 png_crc_finish(png_ptr, length);
1637 return;
1638 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001639
Guy Schalnat0d580581995-07-20 02:43:20 -05001640 if (length != 9)
1641 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001642 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001643 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001644 return;
1645 }
1646
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001647 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001648 if (png_crc_finish(png_ptr, 0))
1649 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001650
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001651 offset_x = png_get_int_32(buf);
1652 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001653 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001654 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1655}
1656#endif
1657
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001658#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001659/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001660void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001661png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1662{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001663 png_int_32 X0, X1;
1664 png_byte type, nparams;
1665 png_charp buf, units, endptr;
1666 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001667 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001668 int i;
1669
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001670 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001671
1672 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1673 png_error(png_ptr, "Missing IHDR before pCAL");
1674 else if (png_ptr->mode & PNG_HAVE_IDAT)
1675 {
1676 png_warning(png_ptr, "Invalid pCAL after IDAT");
1677 png_crc_finish(png_ptr, length);
1678 return;
1679 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001680 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001681 {
1682 png_warning(png_ptr, "Duplicate pCAL chunk");
1683 png_crc_finish(png_ptr, length);
1684 return;
1685 }
1686
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001687 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001688 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001689 png_free(png_ptr, png_ptr->chunkdata);
1690 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1691 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001692 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001693 png_warning(png_ptr, "No memory for pCAL purpose");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001694 return;
1695 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001696 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001697 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001698
1699 if (png_crc_finish(png_ptr, 0))
1700 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001701 png_free(png_ptr, png_ptr->chunkdata);
1702 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001703 return;
1704 }
1705
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001706 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001707
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001708 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001709 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001710 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001711
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001712 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001713
1714 /* We need to have at least 12 bytes after the purpose string
1715 in order to get the parameter information. */
1716 if (endptr <= buf + 12)
1717 {
1718 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001719 png_free(png_ptr, png_ptr->chunkdata);
1720 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001721 return;
1722 }
1723
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001724 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001725 X0 = png_get_int_32((png_bytep)buf+1);
1726 X1 = png_get_int_32((png_bytep)buf+5);
1727 type = buf[9];
1728 nparams = buf[10];
1729 units = buf + 11;
1730
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001731 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001732 /* Check that we have the right number of parameters for known
1733 equation types. */
1734 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1735 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1736 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1737 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1738 {
1739 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001740 png_free(png_ptr, png_ptr->chunkdata);
1741 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001742 return;
1743 }
1744 else if (type >= PNG_EQUATION_LAST)
1745 {
1746 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1747 }
1748
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001749 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001750 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001751
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001752 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001753 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001754 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001755 if (params == NULL)
1756 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001757 png_free(png_ptr, png_ptr->chunkdata);
1758 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001759 png_warning(png_ptr, "No memory for pCAL params");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001760 return;
1761 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001762
1763 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001764 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001765 {
1766 buf++; /* Skip the null string terminator from previous parameter. */
1767
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001768 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001769 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001770 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001771
1772 /* Make sure we haven't run out of data yet */
1773 if (buf > endptr)
1774 {
1775 png_warning(png_ptr, "Invalid pCAL data");
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);
1779 return;
1780 }
1781 }
1782
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001783 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001784 units, params);
1785
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001786 png_free(png_ptr, png_ptr->chunkdata);
1787 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001788 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001789}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001790#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001791
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001792#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001793/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001794void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001795png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1796{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001797 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001798#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001799 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001800 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001801#else
1802#ifdef PNG_FIXED_POINT_SUPPORTED
1803 png_charp swidth, sheight;
1804#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001805#endif
1806 png_size_t slength;
1807
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001808 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001809
1810 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1811 png_error(png_ptr, "Missing IHDR before sCAL");
1812 else if (png_ptr->mode & PNG_HAVE_IDAT)
1813 {
1814 png_warning(png_ptr, "Invalid sCAL after IDAT");
1815 png_crc_finish(png_ptr, length);
1816 return;
1817 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001818 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001819 {
1820 png_warning(png_ptr, "Duplicate sCAL chunk");
1821 png_crc_finish(png_ptr, length);
1822 return;
1823 }
1824
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001825 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001826 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001827 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1828 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001829 {
1830 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1831 return;
1832 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001833 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001834 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001835
1836 if (png_crc_finish(png_ptr, 0))
1837 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001838 png_free(png_ptr, png_ptr->chunkdata);
1839 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001840 return;
1841 }
1842
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001843 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001844
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001845 ep = png_ptr->chunkdata + 1; /* Skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001846
1847#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001848 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001849 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001850 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001851 png_warning(png_ptr, "malformed width string in sCAL chunk");
1852 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001853 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001854#else
1855#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001856 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1857 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001858 {
1859 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1860 return;
1861 }
1862 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001863#endif
1864#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001865
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001866 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001867 /* Empty loop */ ;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001868 ep++;
1869
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001870 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001871 {
1872 png_warning(png_ptr, "Truncated sCAL chunk");
1873#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1874 !defined(PNG_FLOATING_POINT_SUPPORTED)
1875 png_free(png_ptr, swidth);
1876#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001877 png_free(png_ptr, png_ptr->chunkdata);
1878 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001879 return;
1880 }
1881
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001882#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001883 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001884 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001885 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001886 png_warning(png_ptr, "malformed height string in sCAL chunk");
1887 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001888 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001889#else
1890#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001891 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001892 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001893 {
1894 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1895 return;
1896 }
1897 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001898#endif
1899#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001900
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001901 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001902#ifdef PNG_FLOATING_POINT_SUPPORTED
1903 || width <= 0. || height <= 0.
1904#endif
1905 )
1906 {
1907 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001908 png_free(png_ptr, png_ptr->chunkdata);
1909 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001910#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001911 png_free(png_ptr, swidth);
1912 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001913#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001914 return;
1915 }
1916
1917
1918#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001919 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001920#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001921#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001922 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001923#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001924#endif
1925
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001926 png_free(png_ptr, png_ptr->chunkdata);
1927 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001928#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1929 png_free(png_ptr, swidth);
1930 png_free(png_ptr, sheight);
1931#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001932}
1933#endif
1934
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001935#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001936void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001937png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001938{
1939 png_byte buf[7];
1940 png_time mod_time;
1941
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001942 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001943
Guy Schalnate5a37791996-06-05 15:50:50 -05001944 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001945 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001946 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001947 {
1948 png_warning(png_ptr, "Duplicate tIME chunk");
1949 png_crc_finish(png_ptr, length);
1950 return;
1951 }
1952
1953 if (png_ptr->mode & PNG_HAVE_IDAT)
1954 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001955
Guy Schalnat0d580581995-07-20 02:43:20 -05001956 if (length != 7)
1957 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001958 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001959 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001960 return;
1961 }
1962
1963 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001964 if (png_crc_finish(png_ptr, 0))
1965 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001966
1967 mod_time.second = buf[6];
1968 mod_time.minute = buf[5];
1969 mod_time.hour = buf[4];
1970 mod_time.day = buf[3];
1971 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001972 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001973
Andreas Dilger47a0c421997-05-16 02:46:07 -05001974 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001975}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001976#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001977
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001978#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05001979/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001980void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001981png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001982{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001983 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001984 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001985 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001986 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001987 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001988 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001989
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001990 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05001991
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001992#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001993 if (png_ptr->user_chunk_cache_max != 0)
1994 {
1995 if (png_ptr->user_chunk_cache_max == 1)
1996 {
1997 png_crc_finish(png_ptr, length);
1998 return;
1999 }
2000 if (--png_ptr->user_chunk_cache_max == 1)
2001 {
2002 png_warning(png_ptr, "No space in chunk cache for tEXt");
2003 png_crc_finish(png_ptr, length);
2004 return;
2005 }
2006 }
2007#endif
2008
Guy Schalnate5a37791996-06-05 15:50:50 -05002009 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2010 png_error(png_ptr, "Missing IHDR before tEXt");
2011
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002012 if (png_ptr->mode & PNG_HAVE_IDAT)
2013 png_ptr->mode |= PNG_AFTER_IDAT;
2014
Andreas Dilger47a0c421997-05-16 02:46:07 -05002015#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002016 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002017 {
2018 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002019 skip = length - (png_uint_32)65535L;
2020 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002021 }
2022#endif
2023
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002024 png_free(png_ptr, png_ptr->chunkdata);
2025
2026 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2027 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002028 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002029 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002030 return;
2031 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002032 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002033 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002034
2035 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002036 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002037 png_free(png_ptr, png_ptr->chunkdata);
2038 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002039 return;
2040 }
2041
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002042 key = png_ptr->chunkdata;
2043
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002044 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002045
2046 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002047 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002048
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002049 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002050 text++;
2051
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002052 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2053 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002054 if (text_ptr == NULL)
2055 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002056 png_warning(png_ptr, "Not enough memory to process text chunk");
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002057 png_free(png_ptr, png_ptr->chunkdata);
2058 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002059 return;
2060 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002061 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2062 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002063#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002064 text_ptr->lang = NULL;
2065 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002066 text_ptr->itxt_length = 0;
2067#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002068 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002069 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002070
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002071 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002072
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002073 png_free(png_ptr, png_ptr->chunkdata);
2074 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002075 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002076 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002077 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002078}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002079#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002080
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002081#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002082/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002083void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002084png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002085{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002086 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002087 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002088 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002089 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002090 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002091
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002092 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002093
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002094#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002095 if (png_ptr->user_chunk_cache_max != 0)
2096 {
2097 if (png_ptr->user_chunk_cache_max == 1)
2098 {
2099 png_crc_finish(png_ptr, length);
2100 return;
2101 }
2102 if (--png_ptr->user_chunk_cache_max == 1)
2103 {
2104 png_warning(png_ptr, "No space in chunk cache for zTXt");
2105 png_crc_finish(png_ptr, length);
2106 return;
2107 }
2108 }
2109#endif
2110
Guy Schalnate5a37791996-06-05 15:50:50 -05002111 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2112 png_error(png_ptr, "Missing IHDR before zTXt");
2113
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002114 if (png_ptr->mode & PNG_HAVE_IDAT)
2115 png_ptr->mode |= PNG_AFTER_IDAT;
2116
Andreas Dilger47a0c421997-05-16 02:46:07 -05002117#ifdef PNG_MAX_MALLOC_64K
2118 /* We will no doubt have problems with chunks even half this size, but
2119 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002120 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002121 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002122 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002123 png_crc_finish(png_ptr, length);
2124 return;
2125 }
2126#endif
2127
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002128 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002129 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2130 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002131 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002132 png_warning(png_ptr, "Out of memory processing zTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002133 return;
2134 }
2135 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002136 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002137 if (png_crc_finish(png_ptr, 0))
2138 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002139 png_free(png_ptr, png_ptr->chunkdata);
2140 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002141 return;
2142 }
2143
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002144 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002145
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002146 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002147 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002148
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002149 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002150 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002151 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002152 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002153 png_free(png_ptr, png_ptr->chunkdata);
2154 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002155 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002156 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002157 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002158 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002159 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002160 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2161 {
2162 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2163 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2164 }
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002165 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002166 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002167 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002168
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002169 png_decompress_chunk(png_ptr, comp_type,
2170 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002171
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002172 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2173 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002174 if (text_ptr == NULL)
2175 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002176 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002177 png_free(png_ptr, png_ptr->chunkdata);
2178 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002179 return;
2180 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002181 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002182 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002183#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002184 text_ptr->lang = NULL;
2185 text_ptr->lang_key = NULL;
2186 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002187#endif
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002188 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002189 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002190
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002191 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002192
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002193 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002194 png_free(png_ptr, png_ptr->chunkdata);
2195 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002196 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002197 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002198}
2199#endif
2200
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002201#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002202/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002203void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002204png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2205{
2206 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002207 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002208 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002209 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002210 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002211 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002212
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002213 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002214
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002215#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002216 if (png_ptr->user_chunk_cache_max != 0)
2217 {
2218 if (png_ptr->user_chunk_cache_max == 1)
2219 {
2220 png_crc_finish(png_ptr, length);
2221 return;
2222 }
2223 if (--png_ptr->user_chunk_cache_max == 1)
2224 {
2225 png_warning(png_ptr, "No space in chunk cache for iTXt");
2226 png_crc_finish(png_ptr, length);
2227 return;
2228 }
2229 }
2230#endif
2231
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002232 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2233 png_error(png_ptr, "Missing IHDR before iTXt");
2234
2235 if (png_ptr->mode & PNG_HAVE_IDAT)
2236 png_ptr->mode |= PNG_AFTER_IDAT;
2237
2238#ifdef PNG_MAX_MALLOC_64K
2239 /* We will no doubt have problems with chunks even half this size, but
2240 there is no hard and fast rule to tell us where to stop. */
2241 if (length > (png_uint_32)65535L)
2242 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002243 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002244 png_crc_finish(png_ptr, length);
2245 return;
2246 }
2247#endif
2248
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002249 png_free(png_ptr, png_ptr->chunkdata);
2250 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2251 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002252 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002253 png_warning(png_ptr, "No memory to process iTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002254 return;
2255 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002256 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002257 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002258 if (png_crc_finish(png_ptr, 0))
2259 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002260 png_free(png_ptr, png_ptr->chunkdata);
2261 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002262 return;
2263 }
2264
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002265 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002266
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002267 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002268 /* Empty loop */ ;
2269 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002270
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002271 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002272 * translated keyword (possibly empty), and possibly some text after the
2273 * keyword
2274 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002275
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002276 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002277 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002278 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002279 png_free(png_ptr, png_ptr->chunkdata);
2280 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002281 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002282 }
2283 else
2284 {
2285 comp_flag = *lang++;
2286 comp_type = *lang++;
2287 }
2288
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002289 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002290 /* Empty loop */ ;
2291 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002292
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002293 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002294 {
2295 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002296 png_free(png_ptr, png_ptr->chunkdata);
2297 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002298 return;
2299 }
2300
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002301 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002302 /* Empty loop */ ;
2303 text++; /* Skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002304 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002305 {
2306 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002307 png_free(png_ptr, png_ptr->chunkdata);
2308 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002309 return;
2310 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002311
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002312 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002313
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002314 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002315 if (comp_flag)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002316 png_decompress_chunk(png_ptr, comp_type,
2317 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002318 else
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002319 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002320 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2321 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002322 if (text_ptr == NULL)
2323 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002324 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002325 png_free(png_ptr, png_ptr->chunkdata);
2326 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002327 return;
2328 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002329 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002330 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2331 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002332 text_ptr->itxt_length = data_len;
2333 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002334 text_ptr->key = png_ptr->chunkdata;
2335 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002336
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002337 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002338
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002339 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002340 png_free(png_ptr, png_ptr->chunkdata);
2341 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002342 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002343 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002344}
2345#endif
2346
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002347/* This function is called when we haven't found a handler for a
2348 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002349 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2350 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2351 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002352void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002353png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2354{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002355 png_uint_32 skip = 0;
2356
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002357 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002358
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002359#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002360 if (png_ptr->user_chunk_cache_max != 0)
2361 {
2362 if (png_ptr->user_chunk_cache_max == 1)
2363 {
2364 png_crc_finish(png_ptr, length);
2365 return;
2366 }
2367 if (--png_ptr->user_chunk_cache_max == 1)
2368 {
2369 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2370 png_crc_finish(png_ptr, length);
2371 return;
2372 }
2373 }
2374#endif
2375
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002376 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002377 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002378 PNG_IDAT;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002379 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002380 png_ptr->mode |= PNG_AFTER_IDAT;
2381 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002382
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002383 if (!(png_ptr->chunk_name[0] & 0x20))
2384 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002385#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002386 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002387 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002388#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002389 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002390#endif
2391 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002392#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002393 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002394 }
2395
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002396#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002397 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002398#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002399 || (png_ptr->read_user_chunk_fn != NULL)
2400#endif
2401 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002402 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002403#ifdef PNG_MAX_MALLOC_64K
2404 if (length > (png_uint_32)65535L)
2405 {
2406 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2407 skip = length - (png_uint_32)65535L;
2408 length = (png_uint_32)65535L;
2409 }
2410#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002411 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002412 (png_charp)png_ptr->chunk_name,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002413 png_sizeof(png_ptr->unknown_chunk.name));
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002414 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2415 = '\0';
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002416 png_ptr->unknown_chunk.size = (png_size_t)length;
2417 if (length == 0)
2418 png_ptr->unknown_chunk.data = NULL;
2419 else
2420 {
2421 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2422 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
2423 }
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002424#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002425 if (png_ptr->read_user_chunk_fn != NULL)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002426 {
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002427 /* Callback to user unknown chunk handler */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002428 int ret;
2429 ret = (*(png_ptr->read_user_chunk_fn))
2430 (png_ptr, &png_ptr->unknown_chunk);
2431 if (ret < 0)
2432 png_chunk_error(png_ptr, "error in user chunk");
2433 if (ret == 0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002434 {
2435 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002436#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002437 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002438 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002439#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002440 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002441 png_set_unknown_chunks(png_ptr, info_ptr,
2442 &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002443 }
2444 }
2445 else
2446#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002447 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2448 png_free(png_ptr, png_ptr->unknown_chunk.data);
2449 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002450 }
2451 else
2452#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002453 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002454
2455 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002456
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002457#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002458 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002459#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002460}
2461
2462/* This function is called to verify that a chunk name is valid.
2463 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002464 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002465 functions to handle unknown critical chunks after we check that
2466 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002467
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002468#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002469
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002470void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002471png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2472{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002473 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002474 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002475 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002476 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002477 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002478 }
2479}
2480
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002481/* Combines the row recently read in with the existing pixels in the
2482 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002483 This routine also handles the two methods of progressive display
2484 of interlaced images, depending on the mask value.
2485 The mask value describes which pixels are to be combined with
2486 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002487 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002488 a zero indicates the pixel is to be skipped. This is in addition
2489 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002490 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002491
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002492void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002493png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002494{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002495 png_debug(1, "in png_combine_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002496 if (mask == 0xff)
2497 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002498 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002499 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002500 }
2501 else
2502 {
2503 switch (png_ptr->row_info.pixel_depth)
2504 {
2505 case 1:
2506 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002507 png_bytep sp = png_ptr->row_buf + 1;
2508 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002509 int s_inc, s_start, s_end;
2510 int m = 0x80;
2511 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002512 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002513 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002514
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002515#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002516 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002517 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002518 s_start = 0;
2519 s_end = 7;
2520 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002521 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002522 else
2523#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002524 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002525 s_start = 7;
2526 s_end = 0;
2527 s_inc = -1;
2528 }
2529
2530 shift = s_start;
2531
2532 for (i = 0; i < row_width; i++)
2533 {
2534 if (m & mask)
2535 {
2536 int value;
2537
2538 value = (*sp >> shift) & 0x01;
2539 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2540 *dp |= (png_byte)(value << shift);
2541 }
2542
2543 if (shift == s_end)
2544 {
2545 shift = s_start;
2546 sp++;
2547 dp++;
2548 }
2549 else
2550 shift += s_inc;
2551
2552 if (m == 1)
2553 m = 0x80;
2554 else
2555 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002556 }
2557 break;
2558 }
2559 case 2:
2560 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002561 png_bytep sp = png_ptr->row_buf + 1;
2562 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002563 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002564 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002565 int shift;
2566 png_uint_32 i;
2567 png_uint_32 row_width = png_ptr->width;
2568 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002569
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002570#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002571 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002572 {
2573 s_start = 0;
2574 s_end = 6;
2575 s_inc = 2;
2576 }
2577 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002578#endif
2579 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002580 s_start = 6;
2581 s_end = 0;
2582 s_inc = -2;
2583 }
2584
2585 shift = s_start;
2586
2587 for (i = 0; i < row_width; i++)
2588 {
2589 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002590 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002591 value = (*sp >> shift) & 0x03;
2592 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2593 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002594 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002595
2596 if (shift == s_end)
2597 {
2598 shift = s_start;
2599 sp++;
2600 dp++;
2601 }
2602 else
2603 shift += s_inc;
2604 if (m == 1)
2605 m = 0x80;
2606 else
2607 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002608 }
2609 break;
2610 }
2611 case 4:
2612 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002613 png_bytep sp = png_ptr->row_buf + 1;
2614 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002615 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002616 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002617 int shift;
2618 png_uint_32 i;
2619 png_uint_32 row_width = png_ptr->width;
2620 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002621
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002622#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002623 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002624 {
2625 s_start = 0;
2626 s_end = 4;
2627 s_inc = 4;
2628 }
2629 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002630#endif
2631 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002632 s_start = 4;
2633 s_end = 0;
2634 s_inc = -4;
2635 }
2636 shift = s_start;
2637
2638 for (i = 0; i < row_width; i++)
2639 {
2640 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002641 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002642 value = (*sp >> shift) & 0xf;
2643 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2644 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002645 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002646
2647 if (shift == s_end)
2648 {
2649 shift = s_start;
2650 sp++;
2651 dp++;
2652 }
2653 else
2654 shift += s_inc;
2655 if (m == 1)
2656 m = 0x80;
2657 else
2658 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002659 }
2660 break;
2661 }
2662 default:
2663 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002664 png_bytep sp = png_ptr->row_buf + 1;
2665 png_bytep dp = row;
2666 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2667 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002668 png_uint_32 row_width = png_ptr->width;
2669 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002670
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002671
2672 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002673 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002674 if (m & mask)
2675 {
2676 png_memcpy(dp, sp, pixel_bytes);
2677 }
2678
2679 sp += pixel_bytes;
2680 dp += pixel_bytes;
2681
2682 if (m == 1)
2683 m = 0x80;
2684 else
2685 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002686 }
2687 break;
2688 }
2689 }
2690 }
2691}
2692
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002693#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002694/* OLD pre-1.0.9 interface:
2695void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2696 png_uint_32 transformations)
2697 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002698void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002699png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002700{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002701 png_row_infop row_info = &(png_ptr->row_info);
2702 png_bytep row = png_ptr->row_buf + 1;
2703 int pass = png_ptr->pass;
2704 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002705 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2706 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002707 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002708
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002709 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002710 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002711 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002712 png_uint_32 final_width;
2713
2714 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002715
2716 switch (row_info->pixel_depth)
2717 {
2718 case 1:
2719 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002720 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2721 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002722 int sshift, dshift;
2723 int s_start, s_end, s_inc;
2724 int jstop = png_pass_inc[pass];
2725 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002726 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002727 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002728
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002729#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002730 if (transformations & PNG_PACKSWAP)
2731 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002732 sshift = (int)((row_info->width + 7) & 0x07);
2733 dshift = (int)((final_width + 7) & 0x07);
2734 s_start = 7;
2735 s_end = 0;
2736 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002737 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002738 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002739#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002740 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002741 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2742 dshift = 7 - (int)((final_width + 7) & 0x07);
2743 s_start = 0;
2744 s_end = 7;
2745 s_inc = 1;
2746 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002747
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002748 for (i = 0; i < row_info->width; i++)
2749 {
2750 v = (png_byte)((*sp >> sshift) & 0x01);
2751 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002752 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002753 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2754 *dp |= (png_byte)(v << dshift);
2755 if (dshift == s_end)
2756 {
2757 dshift = s_start;
2758 dp--;
2759 }
2760 else
2761 dshift += s_inc;
2762 }
2763 if (sshift == s_end)
2764 {
2765 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002766 sp--;
2767 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002768 else
2769 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002770 }
2771 break;
2772 }
2773 case 2:
2774 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002775 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2776 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2777 int sshift, dshift;
2778 int s_start, s_end, s_inc;
2779 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002780 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002781
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002782#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002783 if (transformations & PNG_PACKSWAP)
2784 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002785 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2786 dshift = (int)(((final_width + 3) & 0x03) << 1);
2787 s_start = 6;
2788 s_end = 0;
2789 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002790 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002791 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002792#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002793 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002794 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2795 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2796 s_start = 0;
2797 s_end = 6;
2798 s_inc = 2;
2799 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002800
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002801 for (i = 0; i < row_info->width; i++)
2802 {
2803 png_byte v;
2804 int j;
2805
2806 v = (png_byte)((*sp >> sshift) & 0x03);
2807 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002808 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002809 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2810 *dp |= (png_byte)(v << dshift);
2811 if (dshift == s_end)
2812 {
2813 dshift = s_start;
2814 dp--;
2815 }
2816 else
2817 dshift += s_inc;
2818 }
2819 if (sshift == s_end)
2820 {
2821 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002822 sp--;
2823 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002824 else
2825 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002826 }
2827 break;
2828 }
2829 case 4:
2830 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002831 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2832 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002833 int sshift, dshift;
2834 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002835 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002836 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002837
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002838#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002839 if (transformations & PNG_PACKSWAP)
2840 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002841 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2842 dshift = (int)(((final_width + 1) & 0x01) << 2);
2843 s_start = 4;
2844 s_end = 0;
2845 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002846 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002847 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002848#endif
2849 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002850 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2851 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2852 s_start = 0;
2853 s_end = 4;
2854 s_inc = 4;
2855 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002856
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002857 for (i = 0; i < row_info->width; i++)
2858 {
2859 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2860 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002861
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002862 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002863 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002864 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2865 *dp |= (png_byte)(v << dshift);
2866 if (dshift == s_end)
2867 {
2868 dshift = s_start;
2869 dp--;
2870 }
2871 else
2872 dshift += s_inc;
2873 }
2874 if (sshift == s_end)
2875 {
2876 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002877 sp--;
2878 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002879 else
2880 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002881 }
2882 break;
2883 }
2884 default:
2885 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002886 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002887 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2888 * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002889 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002890
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002891 int jstop = png_pass_inc[pass];
2892 png_uint_32 i;
2893
2894 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002895 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002896 png_byte v[8];
2897 int j;
2898
2899 png_memcpy(v, sp, pixel_bytes);
2900 for (j = 0; j < jstop; j++)
2901 {
2902 png_memcpy(dp, v, pixel_bytes);
2903 dp -= pixel_bytes;
2904 }
2905 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002906 }
2907 break;
2908 }
2909 }
2910 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002911 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002912 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002913#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002914 transformations = transformations; /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002915#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002916}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002917#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002918
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002919void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002920png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002921 png_bytep prev_row, int filter)
2922{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002923 png_debug(1, "in png_read_filter_row");
2924 png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002925 switch (filter)
2926 {
2927 case PNG_FILTER_VALUE_NONE:
2928 break;
2929 case PNG_FILTER_VALUE_SUB:
2930 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002931 png_uint_32 i;
2932 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002933 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002934 png_bytep rp = row + bpp;
2935 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002936
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002937 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002938 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002939 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2940 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002941 }
2942 break;
2943 }
2944 case PNG_FILTER_VALUE_UP:
2945 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002946 png_uint_32 i;
2947 png_uint_32 istop = row_info->rowbytes;
2948 png_bytep rp = row;
2949 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002950
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002951 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002952 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002953 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2954 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002955 }
2956 break;
2957 }
2958 case PNG_FILTER_VALUE_AVG:
2959 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002960 png_uint_32 i;
2961 png_bytep rp = row;
2962 png_bytep pp = prev_row;
2963 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002964 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002965 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002966
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002967 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002968 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002969 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002970 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002971 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002972 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002973
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002974 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002975 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002976 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002977 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002978 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002979 }
2980 break;
2981 }
2982 case PNG_FILTER_VALUE_PAETH:
2983 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002984 png_uint_32 i;
2985 png_bytep rp = row;
2986 png_bytep pp = prev_row;
2987 png_bytep lp = row;
2988 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002989 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002990 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002991
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002992 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002993 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002994 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2995 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002996 }
2997
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002998 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002999 {
3000 int a, b, c, pa, pb, pc, p;
3001
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003002 a = *lp++;
3003 b = *pp++;
3004 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003005
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003006 p = b - c;
3007 pc = a - c;
3008
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003009#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003010 pa = abs(p);
3011 pb = abs(pc);
3012 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003013#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003014 pa = p < 0 ? -p : p;
3015 pb = pc < 0 ? -pc : pc;
3016 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003017#endif
3018
3019 /*
3020 if (pa <= pb && pa <= pc)
3021 p = a;
3022 else if (pb <= pc)
3023 p = b;
3024 else
3025 p = c;
3026 */
3027
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003028 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003029
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003030 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3031 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003032 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003033 break;
3034 }
3035 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003036 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003037 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003038 break;
3039 }
3040}
Guy Schalnat0d580581995-07-20 02:43:20 -05003041
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003042#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003043void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003044png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003045{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003046#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003047 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003048
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003049 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003050 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003051
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003052 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003053 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003054
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003055 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003056 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003057
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003058 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003059 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3060#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003061
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003062 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003063 png_ptr->row_number++;
3064 if (png_ptr->row_number < png_ptr->num_rows)
3065 return;
3066
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003067#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003068 if (png_ptr->interlaced)
3069 {
3070 png_ptr->row_number = 0;
Glenn Randers-Pehrsona31c74f2009-05-18 15:52:01 -05003071 png_memset(png_ptr->prev_row, 0,
3072 png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003073 do
3074 {
3075 png_ptr->pass++;
3076 if (png_ptr->pass >= 7)
3077 break;
3078 png_ptr->iwidth = (png_ptr->width +
3079 png_pass_inc[png_ptr->pass] - 1 -
3080 png_pass_start[png_ptr->pass]) /
3081 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003082
Guy Schalnat0d580581995-07-20 02:43:20 -05003083 if (!(png_ptr->transformations & PNG_INTERLACE))
3084 {
3085 png_ptr->num_rows = (png_ptr->height +
3086 png_pass_yinc[png_ptr->pass] - 1 -
3087 png_pass_ystart[png_ptr->pass]) /
3088 png_pass_yinc[png_ptr->pass];
3089 if (!(png_ptr->num_rows))
3090 continue;
3091 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003092 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003093 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003094 } while (png_ptr->iwidth == 0);
3095
3096 if (png_ptr->pass < 7)
3097 return;
3098 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003099#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003100
Guy Schalnate5a37791996-06-05 15:50:50 -05003101 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003102 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003103 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003104 char extra;
3105 int ret;
3106
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003107 png_ptr->zstream.next_out = (Byte *)&extra;
3108 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003109 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003111 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003112 {
3113 while (!png_ptr->idat_size)
3114 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003115 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003116
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003117 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003118
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003119 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003120 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003122 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003123 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003124 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003125
3126 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003127 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3128 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05003129 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003130 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3131 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3132 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003133 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003134 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05003135 if (ret == Z_STREAM_END)
3136 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003137 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05003138 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003139 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003140 png_ptr->mode |= PNG_AFTER_IDAT;
3141 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003142 break;
3143 }
3144 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003145 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05003146 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003147
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003148 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003149 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003150 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003151 png_ptr->mode |= PNG_AFTER_IDAT;
3152 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3153 break;
3154 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003155
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003156 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003157 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003158 }
3159
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003160 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003161 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003162
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003163 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003164
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003165 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003166}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003167#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003168
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003169void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003170png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003171{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003172#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003173 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003174
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003175 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003176 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003177
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003178 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003179 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003180
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003181 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003182 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003183
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003184 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003185 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3186#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003187
Guy Schalnat0d580581995-07-20 02:43:20 -05003188 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003189 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003190
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003191 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003192 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003193 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003194#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003195 if (png_ptr->interlaced)
3196 {
3197 if (!(png_ptr->transformations & PNG_INTERLACE))
3198 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
3199 png_pass_ystart[0]) / png_pass_yinc[0];
3200 else
3201 png_ptr->num_rows = png_ptr->height;
3202
3203 png_ptr->iwidth = (png_ptr->width +
3204 png_pass_inc[png_ptr->pass] - 1 -
3205 png_pass_start[png_ptr->pass]) /
3206 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003207 }
3208 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003209#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003210 {
3211 png_ptr->num_rows = png_ptr->height;
3212 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003213 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003214 max_pixel_depth = png_ptr->pixel_depth;
3215
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003216#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003217 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003218 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003219#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003220
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003221#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003222 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003223 {
3224 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3225 {
3226 if (png_ptr->num_trans)
3227 max_pixel_depth = 32;
3228 else
3229 max_pixel_depth = 24;
3230 }
3231 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3232 {
3233 if (max_pixel_depth < 8)
3234 max_pixel_depth = 8;
3235 if (png_ptr->num_trans)
3236 max_pixel_depth *= 2;
3237 }
3238 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3239 {
3240 if (png_ptr->num_trans)
3241 {
3242 max_pixel_depth *= 4;
3243 max_pixel_depth /= 3;
3244 }
3245 }
3246 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003247#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003248
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003249#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003250 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003251 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003252 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3253 max_pixel_depth = 32;
3254 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003255 {
3256 if (max_pixel_depth <= 8)
3257 max_pixel_depth = 16;
3258 else
3259 max_pixel_depth = 32;
3260 }
3261 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3262 {
3263 if (max_pixel_depth <= 32)
3264 max_pixel_depth = 32;
3265 else
3266 max_pixel_depth = 64;
3267 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003268 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003269#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003270
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003271#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003272 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3273 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003274 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003275#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003276 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
3277#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003278#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003279 (png_ptr->transformations & (PNG_FILLER)) ||
3280#endif
3281 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003282 {
3283 if (max_pixel_depth <= 16)
3284 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003285 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003286 max_pixel_depth = 64;
3287 }
3288 else
3289 {
3290 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003291 {
3292 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3293 max_pixel_depth = 32;
3294 else
3295 max_pixel_depth = 24;
3296 }
3297 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3298 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003299 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003300 max_pixel_depth = 48;
3301 }
3302 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003303#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003304
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003305#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3306defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003307 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003308 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003309 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003310 png_ptr->user_transform_channels;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003311 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003312 max_pixel_depth=user_pixel_depth;
3313 }
3314#endif
3315
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003316 /* Align the width on the next larger 8 pixels. Mainly used
3317 * for interlacing
3318 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003319 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003320 /* Calculate the maximum bytes needed, adding a byte and a pixel
3321 * for safety's sake
3322 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003323 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Guy Schalnat0d580581995-07-20 02:43:20 -05003324 1 + ((max_pixel_depth + 7) >> 3);
3325#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003326 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003327 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003328#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003329
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003330 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003331 {
3332 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003333 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003334 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3335 row_bytes + 48);
3336 else
3337 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3338 row_bytes + 48);
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003339 png_ptr->old_big_row_buf_size = row_bytes + 48;
3340
3341#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3342 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3343 * of padding before and after row_buf.
3344 */
3345 png_ptr->row_buf = png_ptr->big_row_buf + 32
3346 - (((png_alloc_size_t)&(png_ptr->big_row_buf[0]) + 15) % 16);
3347 png_ptr->old_big_row_buf_size = row_bytes + 48;
3348#else
3349 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003350 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003351#endif
3352 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003353 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003354
3355#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003356 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003357 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003358#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003359 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003360 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003361
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003362 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003363 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003364 png_free(png_ptr, png_ptr->prev_row);
3365 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003366 png_ptr->rowbytes + 1));
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003367 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003368 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003369
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003370 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003371
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003372 png_debug1(3, "width = %lu,", png_ptr->width);
3373 png_debug1(3, "height = %lu,", png_ptr->height);
3374 png_debug1(3, "iwidth = %lu,", png_ptr->iwidth);
3375 png_debug1(3, "num_rows = %lu,", png_ptr->num_rows);
3376 png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes);
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003377 png_debug1(3, "irowbytes = %lu",
3378 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003379
Guy Schalnate5a37791996-06-05 15:50:50 -05003380 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003381}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003382#endif /* PNG_READ_SUPPORTED */