blob: c8d684b77f3482f0e94a93569b661b2682d94f8c [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-Pehrsona5fa5c92008-09-06 07:06:22 -05004 * Last changed in libpng 1.4.0 [September 6, 2008]
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05006 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050010 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060011 * libpng itself during the course of reading an image.
12 */
Guy Schalnat0d580581995-07-20 02:43:20 -050013
Guy Schalnat0d580581995-07-20 02:43:20 -050014#include "png.h"
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050015#if defined(PNG_READ_SUPPORTED)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050016#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050017
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050018# define png_strtod(p,a,b) strtod(a,b)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060019png_uint_32 PNGAPI
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050020png_get_uint_31(png_structp png_ptr, png_bytep buf)
21{
22 png_uint_32 i = png_get_uint_32(buf);
23 if (i > PNG_UINT_31_MAX)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050024 png_error(png_ptr, "PNG unsigned integer out of range");
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050025 return (i);
26}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050027#ifndef PNG_USE_READ_MACROS
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050028/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060029png_uint_32 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060030png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050031{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050032 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
Guy Schalnat0d580581995-07-20 02:43:20 -050033 ((png_uint_32)(*(buf + 1)) << 16) +
34 ((png_uint_32)(*(buf + 2)) << 8) +
35 (png_uint_32)(*(buf + 3));
36
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060037 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050038}
39
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050040/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050041 * data is stored in the PNG file in two's complement format, and it is
42 * assumed that the machine format for signed integers is the same. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060043png_int_32 PNGAPI
Andreas Dilger47a0c421997-05-16 02:46:07 -050044png_get_int_32(png_bytep buf)
45{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050046 png_int_32 i = ((png_int_32)(*buf) << 24) +
Andreas Dilger47a0c421997-05-16 02:46:07 -050047 ((png_int_32)(*(buf + 1)) << 16) +
48 ((png_int_32)(*(buf + 2)) << 8) +
49 (png_int_32)(*(buf + 3));
50
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060051 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050052}
Andreas Dilger47a0c421997-05-16 02:46:07 -050053
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050054/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060055png_uint_16 PNGAPI
Guy Schalnat6d764711995-12-19 03:22:19 -060056png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050057{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050058 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060059 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050060
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060061 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050062}
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -050063#endif /* PNG_USE_READ_MACROS */
Guy Schalnat0d580581995-07-20 02:43:20 -050064
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050065/* Read the chunk header (length + type name).
66 * Put the type name into png_ptr->chunk_name, and return the length.
67 */
68png_uint_32 /* PRIVATE */
69png_read_chunk_header(png_structp png_ptr)
70{
71 png_byte buf[8];
72 png_uint_32 length;
73
74#ifdef PNG_IO_STATE_SUPPORTED
75 /* Inform the I/O callback that the chunk header is being read.
76 * PNG_IO_CHUNK_HDR requires a single I/O call.
77 */
78 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
79#endif
80
81 /* read the length and the chunk name */
82 png_read_data(png_ptr, buf, 8);
83 length = png_get_uint_31(png_ptr, buf);
84
85 /* put the chunk name into png_ptr->chunk_name */
86 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
87
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -050088 png_debug2(0, "Reading %s chunk, length = %lu",
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050089 png_ptr->chunk_name, length);
90
91 /* reset the crc and run it over the chunk name */
92 png_reset_crc(png_ptr);
93 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
94
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -050095 /* check to see if chunk name is valid */
96 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
97
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050098#ifdef PNG_IO_STATE_SUPPORTED
99 /* Inform the I/O callback that chunk data will (possibly) be read.
100 * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls.
101 */
102 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
103#endif
104
105 return length;
106}
107
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500108/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500109void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500110png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500111{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500112 if (png_ptr == NULL) return;
Guy Schalnat6d764711995-12-19 03:22:19 -0600113 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500114 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500115}
116
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600117/* Optionally skip data and then check the CRC. Depending on whether we
118 are reading a ancillary or critical chunk, and how the program has set
Andreas Dilger47a0c421997-05-16 02:46:07 -0500119 things up, we may calculate the CRC on the data and print a message.
120 Returns '1' if there was a CRC error, '0' otherwise. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500121int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600122png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500123{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500124 png_size_t i;
125 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500126
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500127 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600128 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500129 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500130 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500131 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500132 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500133 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500134 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600135
Andreas Dilger47a0c421997-05-16 02:46:07 -0500136 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600137 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500138 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600139 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500140 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600141 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600142 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600143 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144 }
145 else
146 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500147 png_chunk_benign_error(png_ptr, "CRC error");
148 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600149 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600150 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600151 }
152
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600153 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500154}
155
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600156/* Compare the CRC stored in the PNG file with that calculated by libpng from
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600157 the data it has read thus far. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500158int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600159png_crc_error(png_structp png_ptr)
160{
161 png_byte crc_bytes[4];
162 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500163 int need_crc = 1;
164
165 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
166 {
167 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
168 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
169 need_crc = 0;
170 }
171 else /* critical */
172 {
173 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
174 need_crc = 0;
175 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600176
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500177#ifdef PNG_IO_STATE_SUPPORTED
178 /* inform the I/O callback that the chunk CRC is being read */
179 /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */
180 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
181#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500182
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600183 png_read_data(png_ptr, crc_bytes, 4);
184
Andreas Dilger47a0c421997-05-16 02:46:07 -0500185 if (need_crc)
186 {
187 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600188 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500189 }
190 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600191 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600192}
193
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600194#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500195 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600196/*
197 * Decompress trailing data in a chunk. The assumption is that chunkdata
198 * points at an allocated area holding the contents of a chunk with a
199 * trailing compressed part. What we get back is an allocated area
200 * holding the original prefix part and an uncompressed version of the
201 * trailing part (the malloc area passed in is freed).
202 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500203void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500204png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500205 png_size_t chunklength,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600206 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600207{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500208 static PNG_CONST char msg[] = "Error decoding compressed text";
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500209 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600210 png_size_t text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600211
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600212 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600213 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500214 int ret = Z_OK;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500215 png_ptr->zstream.next_in = (png_bytep)(png_ptr->chunkdata + prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600216 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
217 png_ptr->zstream.next_out = png_ptr->zbuf;
218 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
219
220 text_size = 0;
221 text = NULL;
222
223 while (png_ptr->zstream.avail_in)
224 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500225 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600226 if (ret != Z_OK && ret != Z_STREAM_END)
227 {
228 if (png_ptr->zstream.msg != NULL)
229 png_warning(png_ptr, png_ptr->zstream.msg);
230 else
231 png_warning(png_ptr, msg);
232 inflateReset(&png_ptr->zstream);
233 png_ptr->zstream.avail_in = 0;
234
235 if (text == NULL)
236 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500237 text_size = prefix_size + png_sizeof(msg) + 1;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500238 text = (png_charp)png_malloc_warn(png_ptr, text_size);
239 if (text == NULL)
240 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500241 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -0500242 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500243 png_error(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500244 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500245 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600246 }
247
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500248 text[text_size - 1] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600249
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500250 /* Copy what we can of the error message into the text chunk */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500251 text_size = (png_size_t)(chunklength -
252 (text - png_ptr->chunkdata) - 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500253 if (text_size > png_sizeof(msg))
254 text_size = png_sizeof(msg);
255 png_memcpy(text + prefix_size, msg, text_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600256 break;
257 }
258 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
259 {
260 if (text == NULL)
261 {
262 text_size = prefix_size +
263 png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500264 text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
265 if (text == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500266 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500267 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -0500268 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500269 png_error(png_ptr,
270 "Not enough memory to decompress chunk");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500271 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500272 png_memcpy(text + prefix_size, png_ptr->zbuf,
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500273 text_size - prefix_size);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500274 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500275 *(text + text_size) = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600276 }
277 else
278 {
279 png_charp tmp;
280
281 tmp = text;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500282 text = (png_charp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500283 (png_size_t)(text_size +
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600284 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500285 if (text == NULL)
286 {
287 png_free(png_ptr, tmp);
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500288 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -0500289 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500290 png_error(png_ptr,
291 "Not enough memory to decompress chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500292 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600293 png_memcpy(text, tmp, text_size);
294 png_free(png_ptr, tmp);
295 png_memcpy(text + text_size, png_ptr->zbuf,
296 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
297 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
298 *(text + text_size) = 0x00;
299 }
300 if (ret == Z_STREAM_END)
301 break;
302 else
303 {
304 png_ptr->zstream.next_out = png_ptr->zbuf;
305 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
306 }
307 }
308 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500309 if (ret != Z_STREAM_END)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500310 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500311#if !defined(PNG_NO_STDIO)
Glenn Randers-Pehrsonf46918d2006-06-02 05:31:20 -0500312 char umsg[52];
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500313
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500314 if (ret == Z_BUF_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500315 png_snprintf(umsg, 52,
316 "Buffer error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500317 png_ptr->chunk_name);
318 else if (ret == Z_DATA_ERROR)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500319 png_snprintf(umsg, 52,
320 "Data error in compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500321 png_ptr->chunk_name);
322 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500323 png_snprintf(umsg, 52,
324 "Incomplete compressed datastream in %s chunk",
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500325 png_ptr->chunk_name);
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500326 png_warning(png_ptr, umsg);
327#else
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500328 png_warning(png_ptr,
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500329 "Incomplete compressed datastream in chunk other than IDAT");
330#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500331 text_size = prefix_size;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600332 if (text == NULL)
333 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500334 text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
335 if (text == NULL)
336 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500337 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -0500338 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500339 png_error(png_ptr, "Not enough memory for text");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500340 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500341 png_memcpy(text, png_ptr->chunkdata, prefix_size);
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600342 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500343 *(text + text_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500344 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600345
346 inflateReset(&png_ptr->zstream);
347 png_ptr->zstream.avail_in = 0;
348
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500349 png_free(png_ptr, png_ptr->chunkdata);
350 png_ptr->chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600351 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600352 }
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600353 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600354 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500355#if !defined(PNG_NO_STDIO)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600356 char umsg[50];
357
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500358 png_snprintf(umsg, 50, "Unknown zTXt compression type %d", comp_type);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600359 png_warning(png_ptr, umsg);
360#else
361 png_warning(png_ptr, "Unknown zTXt compression type");
362#endif
363
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500364 *(png_ptr->chunkdata + prefix_size) = 0x00;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500365 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600366 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600367}
368#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600369
Guy Schalnat0d580581995-07-20 02:43:20 -0500370/* read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500371void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600372png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500373{
374 png_byte buf[13];
375 png_uint_32 width, height;
376 int bit_depth, color_type, compression_type, filter_type;
377 int interlace_type;
378
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500379 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500380
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600381 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500382 png_error(png_ptr, "Out of place IHDR");
383
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 /* check the length */
385 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600386 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500387
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600388 png_ptr->mode |= PNG_HAVE_IHDR;
389
Guy Schalnat0d580581995-07-20 02:43:20 -0500390 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600391 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500392
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500393 width = png_get_uint_31(png_ptr, buf);
394 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500395 bit_depth = buf[8];
396 color_type = buf[9];
397 compression_type = buf[10];
398 filter_type = buf[11];
399 interlace_type = buf[12];
400
Guy Schalnat0d580581995-07-20 02:43:20 -0500401 /* set internal variables */
402 png_ptr->width = width;
403 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600404 png_ptr->bit_depth = (png_byte)bit_depth;
405 png_ptr->interlaced = (png_byte)interlace_type;
406 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500407#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600408 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500409#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500410 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500411
412 /* find number of channels */
413 switch (png_ptr->color_type)
414 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500415 case PNG_COLOR_TYPE_GRAY:
416 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500417 png_ptr->channels = 1;
418 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500419 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500420 png_ptr->channels = 3;
421 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500422 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500423 png_ptr->channels = 2;
424 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500425 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500426 png_ptr->channels = 4;
427 break;
428 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600429
Guy Schalnat0d580581995-07-20 02:43:20 -0500430 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600431 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600432 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500433 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500434 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
435 png_debug1(3, "channels = %d", png_ptr->channels);
436 png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500437 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
438 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500439}
440
441/* read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500442void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600443png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500444{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600445 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600446 int num, i;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500447#ifndef PNG_NO_POINTER_INDEXING
448 png_colorp pal_ptr;
449#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500450
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500451 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500452
Guy Schalnate5a37791996-06-05 15:50:50 -0500453 if (!(png_ptr->mode & PNG_HAVE_IHDR))
454 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600455 else if (png_ptr->mode & PNG_HAVE_IDAT)
456 {
457 png_warning(png_ptr, "Invalid PLTE after IDAT");
458 png_crc_finish(png_ptr, length);
459 return;
460 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500461 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600462 png_error(png_ptr, "Duplicate PLTE chunk");
463
464 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500465
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500466 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
467 {
468 png_warning(png_ptr,
469 "Ignoring PLTE chunk in grayscale PNG");
470 png_crc_finish(png_ptr, length);
471 return;
472 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500473#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
474 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
475 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600476 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500477 return;
478 }
479#endif
480
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600481 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500482 {
483 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
484 {
485 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600486 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500487 return;
488 }
489 else
490 {
491 png_error(png_ptr, "Invalid palette chunk");
492 }
493 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500494
495 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500496
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500497#ifndef PNG_NO_POINTER_INDEXING
498 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
499 {
500 png_byte buf[3];
501
502 png_crc_read(png_ptr, buf, 3);
503 pal_ptr->red = buf[0];
504 pal_ptr->green = buf[1];
505 pal_ptr->blue = buf[2];
506 }
507#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600508 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500509 {
510 png_byte buf[3];
511
512 png_crc_read(png_ptr, buf, 3);
513 /* don't depend upon png_color being any order */
514 palette[i].red = buf[0];
515 palette[i].green = buf[1];
516 palette[i].blue = buf[2];
517 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500518#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600519
520 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
521 whatever the normal CRC configuration tells us. However, if we
522 have an RGB image, the PLTE can be considered ancillary, so
523 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600524#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600525 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600526#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600527 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500528 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600529 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600530#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600531 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
532 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600533 /* If we don't want to use the data from an ancillary chunk,
534 we have two options: an error abort, or a warning and we
535 ignore the data in this chunk (which should be OK, since
536 it's considered ancillary for a RGB or RGBA image). */
537 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
538 {
539 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
540 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500541 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600542 }
543 else
544 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600545 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600546 return;
547 }
548 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500549 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600550 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
551 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600552 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600553 }
554 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600555#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500556
Andreas Dilger47a0c421997-05-16 02:46:07 -0500557 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500558
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500559#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500560 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
561 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600562 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500563 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500564 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500565 {
566 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500567 png_ptr->num_trans = (png_uint_16)num;
568 }
569 if (info_ptr->num_trans > (png_uint_16)num)
570 {
571 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
572 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500573 }
574 }
575 }
576#endif
577
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600578}
Guy Schalnate5a37791996-06-05 15:50:50 -0500579
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500580void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600581png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
582{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500583 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500584
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600585 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
586 {
587 png_error(png_ptr, "No image in file");
588 }
589
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600590 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600591
592 if (length != 0)
593 {
594 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600595 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500596 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500597
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500598 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500599}
600
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500601#if defined(PNG_READ_gAMA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500602void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600603png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500604{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600605 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600606#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500607 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600608#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500609 png_byte buf[4];
610
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500611 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500612
Guy Schalnate5a37791996-06-05 15:50:50 -0500613 if (!(png_ptr->mode & PNG_HAVE_IHDR))
614 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600615 else if (png_ptr->mode & PNG_HAVE_IDAT)
616 {
617 png_warning(png_ptr, "Invalid gAMA after IDAT");
618 png_crc_finish(png_ptr, length);
619 return;
620 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500621 else if (png_ptr->mode & PNG_HAVE_PLTE)
622 /* Should be an error, but we can cope with it */
623 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600624
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500625 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600626#if defined(PNG_READ_sRGB_SUPPORTED)
627 && !(info_ptr->valid & PNG_INFO_sRGB)
628#endif
629 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600630 {
631 png_warning(png_ptr, "Duplicate gAMA chunk");
632 png_crc_finish(png_ptr, length);
633 return;
634 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500635
Guy Schalnat0d580581995-07-20 02:43:20 -0500636 if (length != 4)
637 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600638 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600639 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500640 return;
641 }
642
643 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600644 if (png_crc_finish(png_ptr, 0))
645 return;
646
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600647 igamma = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500648 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500649 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500650 {
651 png_warning(png_ptr,
652 "Ignoring gAMA chunk with gamma=0");
653 return;
654 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500655
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600656#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600657 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500658 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600659 {
660 png_warning(png_ptr,
661 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500662#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600663 fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600664#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600665 return;
666 }
667#endif /* PNG_READ_sRGB_SUPPORTED */
668
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600669#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600670 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600671# ifdef PNG_READ_GAMMA_SUPPORTED
672 png_ptr->gamma = file_gamma;
673# endif
674 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600675#endif
676#ifdef PNG_FIXED_POINT_SUPPORTED
677 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
678#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500679}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500680#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500681
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500682#if defined(PNG_READ_sBIT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500683void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600684png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500685{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500686 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600687 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600688
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500689 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500690
Guy Schalnat69b14481996-01-10 02:56:49 -0600691 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500692
Guy Schalnate5a37791996-06-05 15:50:50 -0500693 if (!(png_ptr->mode & PNG_HAVE_IHDR))
694 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600695 else if (png_ptr->mode & PNG_HAVE_IDAT)
696 {
697 png_warning(png_ptr, "Invalid sBIT after IDAT");
698 png_crc_finish(png_ptr, length);
699 return;
700 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500701 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600702 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500703 /* Should be an error, but we can cope with it */
704 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600705 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500706 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600707 {
708 png_warning(png_ptr, "Duplicate sBIT chunk");
709 png_crc_finish(png_ptr, length);
710 return;
711 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500712
Guy Schalnat0d580581995-07-20 02:43:20 -0500713 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600714 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500715 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500716 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500717
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500718 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500719 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600720 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600721 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600722 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500723 }
724
Andreas Dilger47a0c421997-05-16 02:46:07 -0500725 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600726 if (png_crc_finish(png_ptr, 0))
727 return;
728
Guy Schalnat0d580581995-07-20 02:43:20 -0500729 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
730 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600731 png_ptr->sig_bit.red = buf[0];
732 png_ptr->sig_bit.green = buf[1];
733 png_ptr->sig_bit.blue = buf[2];
734 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500735 }
736 else
737 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600738 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600739 png_ptr->sig_bit.red = buf[0];
740 png_ptr->sig_bit.green = buf[0];
741 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600742 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500743 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500744 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500745}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500746#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500747
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500748#if defined(PNG_READ_cHRM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500749void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600750png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500751{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500752 png_byte buf[32];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600753#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500754 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 -0600755#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600756 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 -0600757 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500758
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600759 png_uint_32 uint_x, uint_y;
760
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500761 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500762
Guy Schalnate5a37791996-06-05 15:50:50 -0500763 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600764 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600765 else if (png_ptr->mode & PNG_HAVE_IDAT)
766 {
767 png_warning(png_ptr, "Invalid cHRM after IDAT");
768 png_crc_finish(png_ptr, length);
769 return;
770 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500771 else if (png_ptr->mode & PNG_HAVE_PLTE)
772 /* Should be an error, but we can cope with it */
773 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600774
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500775 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600776#if defined(PNG_READ_sRGB_SUPPORTED)
777 && !(info_ptr->valid & PNG_INFO_sRGB)
778#endif
779 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600780 {
781 png_warning(png_ptr, "Duplicate cHRM chunk");
782 png_crc_finish(png_ptr, length);
783 return;
784 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500785
Guy Schalnat0d580581995-07-20 02:43:20 -0500786 if (length != 32)
787 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600788 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600789 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600790 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500791 }
792
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500793 png_crc_read(png_ptr, buf, 32);
794 if (png_crc_finish(png_ptr, 0))
795 return;
796
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600797 uint_x = png_get_uint_32(buf);
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500798 uint_y = png_get_uint_32(buf + 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600799 if (uint_x > 80000L || uint_y > 80000L ||
800 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600801 {
802 png_warning(png_ptr, "Invalid cHRM white point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600803 return;
804 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600805 int_x_white = (png_fixed_point)uint_x;
806 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500807
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500808 uint_x = png_get_uint_32(buf + 8);
809 uint_y = png_get_uint_32(buf + 12);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600810 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600811 {
812 png_warning(png_ptr, "Invalid cHRM red point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600813 return;
814 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600815 int_x_red = (png_fixed_point)uint_x;
816 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500817
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500818 uint_x = png_get_uint_32(buf + 16);
819 uint_y = png_get_uint_32(buf + 20);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600820 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600821 {
822 png_warning(png_ptr, "Invalid cHRM green point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600823 return;
824 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600825 int_x_green = (png_fixed_point)uint_x;
826 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500827
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500828 uint_x = png_get_uint_32(buf + 24);
829 uint_y = png_get_uint_32(buf + 28);
Glenn Randers-Pehrsonddfebd32006-02-22 09:19:25 -0600830 if (uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600831 {
832 png_warning(png_ptr, "Invalid cHRM blue point");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600833 return;
834 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600835 int_x_blue = (png_fixed_point)uint_x;
836 int_y_blue = (png_fixed_point)uint_y;
837
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600838#ifdef PNG_FLOATING_POINT_SUPPORTED
839 white_x = (float)int_x_white / (float)100000.0;
840 white_y = (float)int_y_white / (float)100000.0;
841 red_x = (float)int_x_red / (float)100000.0;
842 red_y = (float)int_y_red / (float)100000.0;
843 green_x = (float)int_x_green / (float)100000.0;
844 green_y = (float)int_y_green / (float)100000.0;
845 blue_x = (float)int_x_blue / (float)100000.0;
846 blue_y = (float)int_y_blue / (float)100000.0;
847#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600848
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600849#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500850 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600851 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500852 if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
853 PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
854 PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
855 PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
856 PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
857 PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
858 PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
859 PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600860 {
861 png_warning(png_ptr,
862 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500863#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600864#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500865 fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600866 white_x, white_y, red_x, red_y);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500867 fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n",
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600868 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600869#else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500870 fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600871 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500872 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600873 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600874#endif
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500875#endif /* PNG_NO_CONSOLE_IO */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600876 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600877 return;
878 }
879#endif /* PNG_READ_sRGB_SUPPORTED */
880
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600881#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500882 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600883 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600884#endif
885#ifdef PNG_FIXED_POINT_SUPPORTED
886 png_set_cHRM_fixed(png_ptr, info_ptr,
887 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
888 int_y_green, int_x_blue, int_y_blue);
889#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500890}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500891#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500892
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600893#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500894void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600895png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
896{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600897 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600898 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600899
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500900 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600901
902 if (!(png_ptr->mode & PNG_HAVE_IHDR))
903 png_error(png_ptr, "Missing IHDR before sRGB");
904 else if (png_ptr->mode & PNG_HAVE_IDAT)
905 {
906 png_warning(png_ptr, "Invalid sRGB after IDAT");
907 png_crc_finish(png_ptr, length);
908 return;
909 }
910 else if (png_ptr->mode & PNG_HAVE_PLTE)
911 /* Should be an error, but we can cope with it */
912 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600913
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500914 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600915 {
916 png_warning(png_ptr, "Duplicate sRGB chunk");
917 png_crc_finish(png_ptr, length);
918 return;
919 }
920
921 if (length != 1)
922 {
923 png_warning(png_ptr, "Incorrect sRGB chunk length");
924 png_crc_finish(png_ptr, length);
925 return;
926 }
927
928 png_crc_read(png_ptr, buf, 1);
929 if (png_crc_finish(png_ptr, 0))
930 return;
931
932 intent = buf[0];
933 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600934 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600935 {
936 png_warning(png_ptr, "Unknown sRGB intent");
937 return;
938 }
939
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600940#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600941 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600942 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500943 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600944#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500945 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600946#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600947# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500948 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600949# endif
950#endif
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500951 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600952 {
953 png_warning(png_ptr,
954 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500955#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600956# ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500957 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
958 (int)png_ptr->int_gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600959# else
960# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500961 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600962# endif
963# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600964#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600965 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600966 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600967#endif /* PNG_READ_gAMA_SUPPORTED */
968
969#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500970#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600971 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500972 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
973 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
974 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
975 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
976 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
977 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
978 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
979 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600980 {
981 png_warning(png_ptr,
982 "Ignoring incorrect cHRM value when sRGB is also present");
983 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500984#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600985#endif /* PNG_READ_cHRM_SUPPORTED */
986
987 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
988}
989#endif /* PNG_READ_sRGB_SUPPORTED */
990
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600991#if defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500992void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600993png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
994/* Note: this does not properly handle chunks that are > 64K under DOS */
995{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600996 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600997 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600998 png_charp profile;
999 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05001000 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001001 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001002
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001003 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001004
1005 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1006 png_error(png_ptr, "Missing IHDR before iCCP");
1007 else if (png_ptr->mode & PNG_HAVE_IDAT)
1008 {
1009 png_warning(png_ptr, "Invalid iCCP after IDAT");
1010 png_crc_finish(png_ptr, length);
1011 return;
1012 }
1013 else if (png_ptr->mode & PNG_HAVE_PLTE)
1014 /* Should be an error, but we can cope with it */
1015 png_warning(png_ptr, "Out of place iCCP chunk");
1016
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001017 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001018 {
1019 png_warning(png_ptr, "Duplicate iCCP chunk");
1020 png_crc_finish(png_ptr, length);
1021 return;
1022 }
1023
1024#ifdef PNG_MAX_MALLOC_64K
1025 if (length > (png_uint_32)65535L)
1026 {
1027 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1028 skip = length - (png_uint_32)65535L;
1029 length = (png_uint_32)65535L;
1030 }
1031#endif
1032
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001033 png_free(png_ptr, png_ptr->chunkdata);
1034 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001035 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001036 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001037
1038 if (png_crc_finish(png_ptr, skip))
1039 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001040 png_free(png_ptr, png_ptr->chunkdata);
1041 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001042 return;
1043 }
1044
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001045 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001046
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001047 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001048 /* empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001049
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001050 ++profile;
1051
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001052 /* there should be at least one zero (the compression type byte)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001053 following the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001054 if ( profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001055 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001056 png_free(png_ptr, png_ptr->chunkdata);
1057 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001058 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001059 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001060 }
1061
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001062 /* compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001063 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001064 if (compression_type)
1065 {
1066 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001067 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001068 wrote nonzero) */
1069 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001070
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001071 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001072 png_decompress_chunk(png_ptr, compression_type,
1073 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001074
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001075 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001076
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001077 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001078 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001079 png_free(png_ptr, png_ptr->chunkdata);
1080 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001081 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1082 return;
1083 }
1084
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001085 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001086 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson72b63302008-07-22 13:59:07 -05001087 profile_size = ((*(pC ))<<24) |
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001088 ((*(pC + 1))<<16) |
1089 ((*(pC + 2))<< 8) |
1090 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001091
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001092 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001093 profile_length = profile_size;
1094
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001095 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001096 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001097 png_free(png_ptr, png_ptr->chunkdata);
1098 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001099 png_warning(png_ptr, "Ignoring truncated iCCP profile");
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001100 return;
1101 }
1102
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001103 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
1104 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
1105 png_free(png_ptr, png_ptr->chunkdata);
1106 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001107}
1108#endif /* PNG_READ_iCCP_SUPPORTED */
1109
1110#if defined(PNG_READ_sPLT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001111void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001112png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1113/* Note: this does not properly handle chunks that are > 64K under DOS */
1114{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001115 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001116 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001117#ifdef PNG_NO_POINTER_INDEXING
1118 png_sPLT_entryp pp;
1119#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001120 int data_length, entry_size, i;
1121 png_uint_32 skip = 0;
1122 png_size_t slength;
1123
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001124 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001125
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001126#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1127
1128 if (png_ptr->user_chunk_cache_max != 0)
1129 {
1130 if (png_ptr->user_chunk_cache_max == 1)
1131 {
1132 png_crc_finish(png_ptr, length);
1133 return;
1134 }
1135 if (--png_ptr->user_chunk_cache_max == 1)
1136 {
1137 png_warning(png_ptr, "No space in chunk cache for sPLT");
1138 png_crc_finish(png_ptr, length);
1139 return;
1140 }
1141 }
1142#endif
1143
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001144 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1145 png_error(png_ptr, "Missing IHDR before sPLT");
1146 else if (png_ptr->mode & PNG_HAVE_IDAT)
1147 {
1148 png_warning(png_ptr, "Invalid sPLT after IDAT");
1149 png_crc_finish(png_ptr, length);
1150 return;
1151 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001152
1153#ifdef PNG_MAX_MALLOC_64K
1154 if (length > (png_uint_32)65535L)
1155 {
1156 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1157 skip = length - (png_uint_32)65535L;
1158 length = (png_uint_32)65535L;
1159 }
1160#endif
1161
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001162 png_free(png_ptr, png_ptr->chunkdata);
1163 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001164 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001165 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001166
1167 if (png_crc_finish(png_ptr, skip))
1168 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001169 png_free(png_ptr, png_ptr->chunkdata);
1170 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001171 return;
1172 }
1173
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001174 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001175
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001176 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; entry_start++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001177 /* empty loop to find end of name */ ;
1178 ++entry_start;
1179
1180 /* a sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001181 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001182 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001183 png_free(png_ptr, png_ptr->chunkdata);
1184 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001185 png_warning(png_ptr, "malformed sPLT chunk");
1186 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001187 }
1188
1189 new_palette.depth = *entry_start++;
1190 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001191 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001192
1193 /* integrity-check the data length */
1194 if (data_length % entry_size)
1195 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001196 png_free(png_ptr, png_ptr->chunkdata);
1197 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001198 png_warning(png_ptr, "sPLT chunk has bad length");
1199 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001200 }
1201
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06001202 new_palette.nentries = (png_int_32) ( data_length / entry_size);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001203 if ((png_uint_32) new_palette.nentries >
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001204 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001205 {
1206 png_warning(png_ptr, "sPLT chunk too long");
1207 return;
1208 }
1209 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001210 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001211 if (new_palette.entries == NULL)
1212 {
1213 png_warning(png_ptr, "sPLT chunk requires too much memory");
1214 return;
1215 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001216
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001217#ifndef PNG_NO_POINTER_INDEXING
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001218 for (i = 0; i < new_palette.nentries; i++)
1219 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001220 png_sPLT_entryp pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001221
1222 if (new_palette.depth == 8)
1223 {
1224 pp->red = *entry_start++;
1225 pp->green = *entry_start++;
1226 pp->blue = *entry_start++;
1227 pp->alpha = *entry_start++;
1228 }
1229 else
1230 {
1231 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1232 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1233 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1234 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1235 }
1236 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1237 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001238#else
1239 pp = new_palette.entries;
1240 for (i = 0; i < new_palette.nentries; i++)
1241 {
1242
1243 if (new_palette.depth == 8)
1244 {
1245 pp[i].red = *entry_start++;
1246 pp[i].green = *entry_start++;
1247 pp[i].blue = *entry_start++;
1248 pp[i].alpha = *entry_start++;
1249 }
1250 else
1251 {
1252 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1253 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1254 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1255 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1256 }
1257 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1258 }
1259#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001260
1261 /* discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001262 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001263
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001264 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001265
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001266 png_free(png_ptr, png_ptr->chunkdata);
1267 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001268 png_free(png_ptr, new_palette.entries);
1269}
1270#endif /* PNG_READ_sPLT_SUPPORTED */
1271
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001272#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001273void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001274png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001275{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001276 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001277
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001278 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001279
Guy Schalnate5a37791996-06-05 15:50:50 -05001280 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1281 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001282 else if (png_ptr->mode & PNG_HAVE_IDAT)
1283 {
1284 png_warning(png_ptr, "Invalid tRNS after IDAT");
1285 png_crc_finish(png_ptr, length);
1286 return;
1287 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001288 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001289 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001290 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001291 png_crc_finish(png_ptr, length);
1292 return;
1293 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001294
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001295 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001296 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001297 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001298
1299 if (length != 2)
1300 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001301 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001302 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001303 return;
1304 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001305
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001306 png_crc_read(png_ptr, buf, 2);
1307 png_ptr->num_trans = 1;
1308 png_ptr->trans_values.gray = png_get_uint_16(buf);
1309 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001310 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1311 {
1312 png_byte buf[6];
1313
1314 if (length != 6)
1315 {
1316 png_warning(png_ptr, "Incorrect tRNS chunk length");
1317 png_crc_finish(png_ptr, length);
1318 return;
1319 }
1320 png_crc_read(png_ptr, buf, (png_size_t)length);
1321 png_ptr->num_trans = 1;
1322 png_ptr->trans_values.red = png_get_uint_16(buf);
1323 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1324 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1325 }
1326 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1327 {
1328 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1329 {
1330 /* Should be an error, but we can cope with it. */
1331 png_warning(png_ptr, "Missing PLTE before tRNS");
1332 }
1333 if (length > (png_uint_32)png_ptr->num_palette ||
1334 length > PNG_MAX_PALETTE_LENGTH)
1335 {
1336 png_warning(png_ptr, "Incorrect tRNS chunk length");
1337 png_crc_finish(png_ptr, length);
1338 return;
1339 }
1340 if (length == 0)
1341 {
1342 png_warning(png_ptr, "Zero length tRNS chunk");
1343 png_crc_finish(png_ptr, length);
1344 return;
1345 }
1346 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1347 png_ptr->num_trans = (png_uint_16)length;
1348 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001349 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001350 {
1351 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001352 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001353 return;
1354 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001355
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001356 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001357 {
1358 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001359 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001360 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001361
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001362 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -05001363 &(png_ptr->trans_values));
1364}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001365#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001366
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001367#if defined(PNG_READ_bKGD_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001368void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001369png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001370{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001371 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001372 png_byte buf[6];
1373
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001374 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001375
Guy Schalnate5a37791996-06-05 15:50:50 -05001376 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1377 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001378 else if (png_ptr->mode & PNG_HAVE_IDAT)
1379 {
1380 png_warning(png_ptr, "Invalid bKGD after IDAT");
1381 png_crc_finish(png_ptr, length);
1382 return;
1383 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001384 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1385 !(png_ptr->mode & PNG_HAVE_PLTE))
1386 {
1387 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001388 png_crc_finish(png_ptr, length);
1389 return;
1390 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001391 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001392 {
1393 png_warning(png_ptr, "Duplicate bKGD chunk");
1394 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001395 return;
1396 }
1397
Guy Schalnat0d580581995-07-20 02:43:20 -05001398 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1399 truelen = 1;
1400 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1401 truelen = 6;
1402 else
1403 truelen = 2;
1404
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001405 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001406 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001407 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001408 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001409 return;
1410 }
1411
Andreas Dilger47a0c421997-05-16 02:46:07 -05001412 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001413 if (png_crc_finish(png_ptr, 0))
1414 return;
1415
Guy Schalnate5a37791996-06-05 15:50:50 -05001416 /* We convert the index value into RGB components so that we can allow
1417 * arbitrary RGB values for background when we have transparency, and
1418 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001419 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001420 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001421 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001422 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001423 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001424 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001425 if (buf[0] > info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001426 {
1427 png_warning(png_ptr, "Incorrect bKGD chunk index value");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001428 return;
1429 }
1430 png_ptr->background.red =
1431 (png_uint_16)png_ptr->palette[buf[0]].red;
1432 png_ptr->background.green =
1433 (png_uint_16)png_ptr->palette[buf[0]].green;
1434 png_ptr->background.blue =
1435 (png_uint_16)png_ptr->palette[buf[0]].blue;
1436 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001437 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001438 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001439 {
1440 png_ptr->background.red =
1441 png_ptr->background.green =
1442 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001443 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001444 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001445 else
1446 {
1447 png_ptr->background.red = png_get_uint_16(buf);
1448 png_ptr->background.green = png_get_uint_16(buf + 2);
1449 png_ptr->background.blue = png_get_uint_16(buf + 4);
1450 }
1451
Andreas Dilger47a0c421997-05-16 02:46:07 -05001452 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001453}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001454#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001455
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001456#if defined(PNG_READ_hIST_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001457void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001458png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001459{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001460 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001461 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001462
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001463 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001464
Guy Schalnate5a37791996-06-05 15:50:50 -05001465 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1466 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001467 else if (png_ptr->mode & PNG_HAVE_IDAT)
1468 {
1469 png_warning(png_ptr, "Invalid hIST after IDAT");
1470 png_crc_finish(png_ptr, length);
1471 return;
1472 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001473 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1474 {
1475 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001476 png_crc_finish(png_ptr, length);
1477 return;
1478 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001479 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001480 {
1481 png_warning(png_ptr, "Duplicate hIST chunk");
1482 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001483 return;
1484 }
1485
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001486 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001487 if (num != (unsigned int) png_ptr->num_palette || num >
1488 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001489 {
1490 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001491 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001492 return;
1493 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001494
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001495 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001496 {
1497 png_byte buf[2];
1498
1499 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001500 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001501 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001502
1503 if (png_crc_finish(png_ptr, 0))
1504 return;
1505
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001506 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001507}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001508#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001509
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001510#if defined(PNG_READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001511void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001512png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001513{
1514 png_byte buf[9];
1515 png_uint_32 res_x, res_y;
1516 int unit_type;
1517
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001518 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001519
Guy Schalnate5a37791996-06-05 15:50:50 -05001520 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001521 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001522 else if (png_ptr->mode & PNG_HAVE_IDAT)
1523 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001524 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001525 png_crc_finish(png_ptr, length);
1526 return;
1527 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001528 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001529 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001530 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001531 png_crc_finish(png_ptr, length);
1532 return;
1533 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001534
Guy Schalnat0d580581995-07-20 02:43:20 -05001535 if (length != 9)
1536 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001537 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001538 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001539 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001540 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001541
1542 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001543 if (png_crc_finish(png_ptr, 0))
1544 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001545
1546 res_x = png_get_uint_32(buf);
1547 res_y = png_get_uint_32(buf + 4);
1548 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001549 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001550}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001551#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001552
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001553#if defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001554void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001555png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001556{
1557 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001558 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001559 int unit_type;
1560
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001561 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562
Guy Schalnate5a37791996-06-05 15:50:50 -05001563 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1564 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001565 else if (png_ptr->mode & PNG_HAVE_IDAT)
1566 {
1567 png_warning(png_ptr, "Invalid oFFs after IDAT");
1568 png_crc_finish(png_ptr, length);
1569 return;
1570 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001571 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001572 {
1573 png_warning(png_ptr, "Duplicate oFFs chunk");
1574 png_crc_finish(png_ptr, length);
1575 return;
1576 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001577
Guy Schalnat0d580581995-07-20 02:43:20 -05001578 if (length != 9)
1579 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001580 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001581 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001582 return;
1583 }
1584
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001585 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001586 if (png_crc_finish(png_ptr, 0))
1587 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001588
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001589 offset_x = png_get_int_32(buf);
1590 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001591 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001592 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1593}
1594#endif
1595
1596#if defined(PNG_READ_pCAL_SUPPORTED)
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001597/* read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001598void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001599png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1600{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001601 png_int_32 X0, X1;
1602 png_byte type, nparams;
1603 png_charp buf, units, endptr;
1604 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001605 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001606 int i;
1607
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001608 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001609
1610 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1611 png_error(png_ptr, "Missing IHDR before pCAL");
1612 else if (png_ptr->mode & PNG_HAVE_IDAT)
1613 {
1614 png_warning(png_ptr, "Invalid pCAL after IDAT");
1615 png_crc_finish(png_ptr, length);
1616 return;
1617 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001618 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001619 {
1620 png_warning(png_ptr, "Duplicate pCAL chunk");
1621 png_crc_finish(png_ptr, length);
1622 return;
1623 }
1624
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001625 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001626 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001627 png_free(png_ptr, png_ptr->chunkdata);
1628 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1629 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001630 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001631 png_warning(png_ptr, "No memory for pCAL purpose");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001632 return;
1633 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001634 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001635 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001636
1637 if (png_crc_finish(png_ptr, 0))
1638 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001639 png_free(png_ptr, png_ptr->chunkdata);
1640 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001641 return;
1642 }
1643
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001644 png_ptr->chunkdata[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001645
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001646 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001647 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001648 /* empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001649
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001650 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001651
1652 /* We need to have at least 12 bytes after the purpose string
1653 in order to get the parameter information. */
1654 if (endptr <= buf + 12)
1655 {
1656 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001657 png_free(png_ptr, png_ptr->chunkdata);
1658 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001659 return;
1660 }
1661
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001662 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001663 X0 = png_get_int_32((png_bytep)buf+1);
1664 X1 = png_get_int_32((png_bytep)buf+5);
1665 type = buf[9];
1666 nparams = buf[10];
1667 units = buf + 11;
1668
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001669 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001670 /* Check that we have the right number of parameters for known
1671 equation types. */
1672 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1673 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1674 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1675 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1676 {
1677 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001678 png_free(png_ptr, png_ptr->chunkdata);
1679 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001680 return;
1681 }
1682 else if (type >= PNG_EQUATION_LAST)
1683 {
1684 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1685 }
1686
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001687 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001688 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001689
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001690 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001691 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001692 (png_size_t)(nparams * png_sizeof(png_charp)));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001693 if (params == NULL)
1694 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001695 png_free(png_ptr, png_ptr->chunkdata);
1696 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001697 png_warning(png_ptr, "No memory for pCAL params");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001698 return;
1699 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001700
1701 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001702 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001703 {
1704 buf++; /* Skip the null string terminator from previous parameter. */
1705
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001706 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001707 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001708 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001709
1710 /* Make sure we haven't run out of data yet */
1711 if (buf > endptr)
1712 {
1713 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001714 png_free(png_ptr, png_ptr->chunkdata);
1715 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001716 png_free(png_ptr, params);
1717 return;
1718 }
1719 }
1720
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001721 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001722 units, params);
1723
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001724 png_free(png_ptr, png_ptr->chunkdata);
1725 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001726 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001727}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001728#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001729
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001730#if defined(PNG_READ_sCAL_SUPPORTED)
1731/* read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001732void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001733png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1734{
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001735 png_charp ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001736#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001737 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001738 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001739#else
1740#ifdef PNG_FIXED_POINT_SUPPORTED
1741 png_charp swidth, sheight;
1742#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001743#endif
1744 png_size_t slength;
1745
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001746 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001747
1748 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1749 png_error(png_ptr, "Missing IHDR before sCAL");
1750 else if (png_ptr->mode & PNG_HAVE_IDAT)
1751 {
1752 png_warning(png_ptr, "Invalid sCAL after IDAT");
1753 png_crc_finish(png_ptr, length);
1754 return;
1755 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001756 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001757 {
1758 png_warning(png_ptr, "Duplicate sCAL chunk");
1759 png_crc_finish(png_ptr, length);
1760 return;
1761 }
1762
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001763 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001764 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001765 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1766 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001767 {
1768 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1769 return;
1770 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001771 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001772 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001773
1774 if (png_crc_finish(png_ptr, 0))
1775 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001776 png_free(png_ptr, png_ptr->chunkdata);
1777 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001778 return;
1779 }
1780
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001781 png_ptr->chunkdata[slength] = 0x00; /* null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001782
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001783 ep = png_ptr->chunkdata + 1; /* skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001784
1785#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001786 width = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001787 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001788 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001789 png_warning(png_ptr, "malformed width string in sCAL chunk");
1790 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001791 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001792#else
1793#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001794 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1795 if (swidth == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001796 {
1797 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1798 return;
1799 }
1800 png_memcpy(swidth, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001801#endif
1802#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001803
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001804 for (ep = png_ptr->chunkdata; *ep; ep++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001805 /* empty loop */ ;
1806 ep++;
1807
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001808 if (png_ptr->chunkdata + slength < ep)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001809 {
1810 png_warning(png_ptr, "Truncated sCAL chunk");
1811#if defined(PNG_FIXED_POINT_SUPPORTED) && \
1812 !defined(PNG_FLOATING_POINT_SUPPORTED)
1813 png_free(png_ptr, swidth);
1814#endif
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001815 png_free(png_ptr, png_ptr->chunkdata);
1816 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001817 return;
1818 }
1819
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001820#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001821 height = png_strtod(png_ptr, ep, &vp);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001822 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001823 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001824 png_warning(png_ptr, "malformed height string in sCAL chunk");
1825 return;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001826 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001827#else
1828#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001829 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001830 if (sheight == NULL)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001831 {
1832 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1833 return;
1834 }
1835 png_memcpy(sheight, ep, png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001836#endif
1837#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001838
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001839 if (png_ptr->chunkdata + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001840#ifdef PNG_FLOATING_POINT_SUPPORTED
1841 || width <= 0. || height <= 0.
1842#endif
1843 )
1844 {
1845 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001846 png_free(png_ptr, png_ptr->chunkdata);
1847 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001848#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001849 png_free(png_ptr, swidth);
1850 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001851#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001852 return;
1853 }
1854
1855
1856#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001857 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001858#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001859#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001860 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001861#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001862#endif
1863
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001864 png_free(png_ptr, png_ptr->chunkdata);
1865 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001866#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1867 png_free(png_ptr, swidth);
1868 png_free(png_ptr, sheight);
1869#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001870}
1871#endif
1872
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001873#if defined(PNG_READ_tIME_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001874void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001875png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001876{
1877 png_byte buf[7];
1878 png_time mod_time;
1879
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001880 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001881
Guy Schalnate5a37791996-06-05 15:50:50 -05001882 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001883 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001884 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001885 {
1886 png_warning(png_ptr, "Duplicate tIME chunk");
1887 png_crc_finish(png_ptr, length);
1888 return;
1889 }
1890
1891 if (png_ptr->mode & PNG_HAVE_IDAT)
1892 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001893
Guy Schalnat0d580581995-07-20 02:43:20 -05001894 if (length != 7)
1895 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001896 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001897 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001898 return;
1899 }
1900
1901 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001902 if (png_crc_finish(png_ptr, 0))
1903 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001904
1905 mod_time.second = buf[6];
1906 mod_time.minute = buf[5];
1907 mod_time.hour = buf[4];
1908 mod_time.day = buf[3];
1909 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001910 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001911
Andreas Dilger47a0c421997-05-16 02:46:07 -05001912 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001913}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001914#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001915
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001916#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001917/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001918void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001919png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001920{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001921 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001922 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001923 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001924 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001925 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001926 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001927
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001928 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05001929
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001930#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1931 if (png_ptr->user_chunk_cache_max != 0)
1932 {
1933 if (png_ptr->user_chunk_cache_max == 1)
1934 {
1935 png_crc_finish(png_ptr, length);
1936 return;
1937 }
1938 if (--png_ptr->user_chunk_cache_max == 1)
1939 {
1940 png_warning(png_ptr, "No space in chunk cache for tEXt");
1941 png_crc_finish(png_ptr, length);
1942 return;
1943 }
1944 }
1945#endif
1946
Guy Schalnate5a37791996-06-05 15:50:50 -05001947 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1948 png_error(png_ptr, "Missing IHDR before tEXt");
1949
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001950 if (png_ptr->mode & PNG_HAVE_IDAT)
1951 png_ptr->mode |= PNG_AFTER_IDAT;
1952
Andreas Dilger47a0c421997-05-16 02:46:07 -05001953#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001954 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001955 {
1956 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001957 skip = length - (png_uint_32)65535L;
1958 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001959 }
1960#endif
1961
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001962 key = (png_charp)png_malloc_warn(png_ptr, length + 1);
1963 if (key == NULL)
1964 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001965 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001966 return;
1967 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001968 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001969 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001970
1971 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001972 {
1973 png_free(png_ptr, key);
1974 return;
1975 }
1976
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001977 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001978
1979 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001980 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001981
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001982 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001983 text++;
1984
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001985 text_ptr = (png_textp)png_malloc_warn(png_ptr,
1986 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001987 if (text_ptr == NULL)
1988 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001989 png_warning(png_ptr, "Not enough memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001990 png_free(png_ptr, key);
1991 return;
1992 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001993 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1994 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001995#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001996 text_ptr->lang = NULL;
1997 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001998 text_ptr->itxt_length = 0;
1999#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002000 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002001 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002002
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002003 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002004
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -05002005 png_free(png_ptr, key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002006 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002007 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002008 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002009}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002010#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002011
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002012#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002013/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002014void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002015png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002016{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002017 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002018 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002019 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002020 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002021 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002022
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002023 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002024
2025#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2026 if (png_ptr->user_chunk_cache_max != 0)
2027 {
2028 if (png_ptr->user_chunk_cache_max == 1)
2029 {
2030 png_crc_finish(png_ptr, length);
2031 return;
2032 }
2033 if (--png_ptr->user_chunk_cache_max == 1)
2034 {
2035 png_warning(png_ptr, "No space in chunk cache for zTXt");
2036 png_crc_finish(png_ptr, length);
2037 return;
2038 }
2039 }
2040#endif
2041
Guy Schalnate5a37791996-06-05 15:50:50 -05002042 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2043 png_error(png_ptr, "Missing IHDR before zTXt");
2044
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002045 if (png_ptr->mode & PNG_HAVE_IDAT)
2046 png_ptr->mode |= PNG_AFTER_IDAT;
2047
Andreas Dilger47a0c421997-05-16 02:46:07 -05002048#ifdef PNG_MAX_MALLOC_64K
2049 /* We will no doubt have problems with chunks even half this size, but
2050 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002051 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002052 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002053 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002054 png_crc_finish(png_ptr, length);
2055 return;
2056 }
2057#endif
2058
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002059 png_free(png_ptr,png_ptr->chunkdata);
2060 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2061 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002062 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002063 png_warning(png_ptr, "Out of memory processing zTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002064 return;
2065 }
2066 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002067 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002068 if (png_crc_finish(png_ptr, 0))
2069 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002070 png_free(png_ptr, png_ptr->chunkdata);
2071 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002072 return;
2073 }
2074
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002075 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002076
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002077 for (text = png_ptr->chunkdata; *text; text++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002078 /* empty loop */ ;
2079
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002080 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002081 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002082 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002083 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002084 png_free(png_ptr, png_ptr->chunkdata);
2085 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002086 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002087 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002088 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002089 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002090 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002091 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2092 {
2093 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2094 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2095 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002096 text++; /* skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002097 }
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002098 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002099
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002100 png_decompress_chunk(png_ptr, comp_type,
2101 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002102
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002103 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2104 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002105 if (text_ptr == NULL)
2106 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002107 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002108 png_free(png_ptr, png_ptr->chunkdata);
2109 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002110 return;
2111 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002112 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002113 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002114#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002115 text_ptr->lang = NULL;
2116 text_ptr->lang_key = NULL;
2117 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002118#endif
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002119 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002120 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002121
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002122 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002123
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002124 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002125 png_free(png_ptr, png_ptr->chunkdata);
2126 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002127 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002128 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002129}
2130#endif
2131
2132#if defined(PNG_READ_iTXt_SUPPORTED)
2133/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002134void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002135png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2136{
2137 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002138 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002139 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002140 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002141 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002142 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002143
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002144 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002145
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002146#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2147 if (png_ptr->user_chunk_cache_max != 0)
2148 {
2149 if (png_ptr->user_chunk_cache_max == 1)
2150 {
2151 png_crc_finish(png_ptr, length);
2152 return;
2153 }
2154 if (--png_ptr->user_chunk_cache_max == 1)
2155 {
2156 png_warning(png_ptr, "No space in chunk cache for iTXt");
2157 png_crc_finish(png_ptr, length);
2158 return;
2159 }
2160 }
2161#endif
2162
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002163 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2164 png_error(png_ptr, "Missing IHDR before iTXt");
2165
2166 if (png_ptr->mode & PNG_HAVE_IDAT)
2167 png_ptr->mode |= PNG_AFTER_IDAT;
2168
2169#ifdef PNG_MAX_MALLOC_64K
2170 /* We will no doubt have problems with chunks even half this size, but
2171 there is no hard and fast rule to tell us where to stop. */
2172 if (length > (png_uint_32)65535L)
2173 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002174 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002175 png_crc_finish(png_ptr, length);
2176 return;
2177 }
2178#endif
2179
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002180 png_free(png_ptr, png_ptr->chunkdata);
2181 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2182 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002183 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002184 png_warning(png_ptr, "No memory to process iTXt chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002185 return;
2186 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002187 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002188 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002189 if (png_crc_finish(png_ptr, 0))
2190 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002191 png_free(png_ptr, png_ptr->chunkdata);
2192 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002193 return;
2194 }
2195
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002196 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002197
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002198 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002199 /* empty loop */ ;
2200 lang++; /* skip NUL separator */
2201
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002202 /* iTXt must have a language tag (possibly empty), two compression bytes,
2203 translated keyword (possibly empty), and possibly some text after the
2204 keyword */
2205
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002206 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002207 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002208 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002209 png_free(png_ptr, png_ptr->chunkdata);
2210 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002211 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002212 }
2213 else
2214 {
2215 comp_flag = *lang++;
2216 comp_type = *lang++;
2217 }
2218
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002219 for (lang_key = lang; *lang_key; lang_key++)
2220 /* empty loop */ ;
2221 lang_key++; /* skip NUL separator */
2222
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002223 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002224 {
2225 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002226 png_free(png_ptr, png_ptr->chunkdata);
2227 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002228 return;
2229 }
2230
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002231 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002232 /* empty loop */ ;
2233 text++; /* skip NUL separator */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002234 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002235 {
2236 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002237 png_free(png_ptr, png_ptr->chunkdata);
2238 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002239 return;
2240 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002241
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002242 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002243
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002244 key=png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002245 if (comp_flag)
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002246 png_decompress_chunk(png_ptr, comp_type,
2247 (size_t)length, prefix_len, &data_len);
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002248 else
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002249 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002250 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2251 png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002252 if (text_ptr == NULL)
2253 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002254 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002255 png_free(png_ptr, png_ptr->chunkdata);
2256 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002257 return;
2258 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002259 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002260 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2261 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002262 text_ptr->itxt_length = data_len;
2263 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002264 text_ptr->key = png_ptr->chunkdata;
2265 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002266
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002267 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002268
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002269 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002270 png_free(png_ptr, png_ptr->chunkdata);
2271 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002272 if (ret)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002273 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002274}
2275#endif
2276
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002277/* This function is called when we haven't found a handler for a
2278 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002279 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2280 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2281 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002282void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002283png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2284{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002285 png_uint_32 skip = 0;
2286
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002287 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002288
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002289#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2290 if (png_ptr->user_chunk_cache_max != 0)
2291 {
2292 if (png_ptr->user_chunk_cache_max == 1)
2293 {
2294 png_crc_finish(png_ptr, length);
2295 return;
2296 }
2297 if (--png_ptr->user_chunk_cache_max == 1)
2298 {
2299 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2300 png_crc_finish(png_ptr, length);
2301 return;
2302 }
2303 }
2304#endif
2305
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002306 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002307 {
2308#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002309 PNG_CONST PNG_IDAT;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002310#endif
2311 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
2312 png_ptr->mode |= PNG_AFTER_IDAT;
2313 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002314
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002315 if (!(png_ptr->chunk_name[0] & 0x20))
2316 {
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002317#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002318 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002319 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002320#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002321 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002322#endif
2323 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002324#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002325 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002326 }
2327
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002328#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06002329 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) ||
2330 (png_ptr->read_user_chunk_fn != NULL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002331 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002332#ifdef PNG_MAX_MALLOC_64K
2333 if (length > (png_uint_32)65535L)
2334 {
2335 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2336 skip = length - (png_uint_32)65535L;
2337 length = (png_uint_32)65535L;
2338 }
2339#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002340 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2341 (png_charp)png_ptr->chunk_name,
2342 png_sizeof(png_ptr->unknown_chunk.name));
2343 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] = '\0';
2344 png_ptr->unknown_chunk.size = (png_size_t)length;
2345 if (length == 0)
2346 png_ptr->unknown_chunk.data = NULL;
2347 else
2348 {
2349 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2350 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
2351 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002352#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002353 if (png_ptr->read_user_chunk_fn != NULL)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002354 {
2355 /* callback to user unknown chunk handler */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002356 int ret;
2357 ret = (*(png_ptr->read_user_chunk_fn))
2358 (png_ptr, &png_ptr->unknown_chunk);
2359 if (ret < 0)
2360 png_chunk_error(png_ptr, "error in user chunk");
2361 if (ret == 0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002362 {
2363 if (!(png_ptr->chunk_name[0] & 0x20))
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002364 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrsondff799e2004-08-07 21:42:49 -05002365 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002366 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002367 png_set_unknown_chunks(png_ptr, info_ptr,
2368 &png_ptr->unknown_chunk, 1);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002369 }
2370 }
2371 else
2372#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002373 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2374 png_free(png_ptr, png_ptr->unknown_chunk.data);
2375 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002376 }
2377 else
2378#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002379 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002380
2381 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002382
2383#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002384 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002385#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002386}
2387
2388/* This function is called to verify that a chunk name is valid.
2389 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002390 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002391 functions to handle unknown critical chunks after we check that
2392 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002393
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002394#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002395
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002396void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002397png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2398{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002399 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002400 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002401 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002402 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002403 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002404 }
2405}
2406
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002407/* Combines the row recently read in with the existing pixels in the
2408 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002409 This routine also handles the two methods of progressive display
2410 of interlaced images, depending on the mask value.
2411 The mask value describes which pixels are to be combined with
2412 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002413 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002414 a zero indicates the pixel is to be skipped. This is in addition
2415 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002416 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002417
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002418void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002419png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002420{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002421 png_debug(1, "in png_combine_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002422 if (mask == 0xff)
2423 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002424 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002425 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002426 }
2427 else
2428 {
2429 switch (png_ptr->row_info.pixel_depth)
2430 {
2431 case 1:
2432 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002433 png_bytep sp = png_ptr->row_buf + 1;
2434 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002435 int s_inc, s_start, s_end;
2436 int m = 0x80;
2437 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002438 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002439 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002440
Andreas Dilger47a0c421997-05-16 02:46:07 -05002441#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2442 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002443 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002444 s_start = 0;
2445 s_end = 7;
2446 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002447 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002448 else
2449#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002450 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002451 s_start = 7;
2452 s_end = 0;
2453 s_inc = -1;
2454 }
2455
2456 shift = s_start;
2457
2458 for (i = 0; i < row_width; i++)
2459 {
2460 if (m & mask)
2461 {
2462 int value;
2463
2464 value = (*sp >> shift) & 0x01;
2465 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2466 *dp |= (png_byte)(value << shift);
2467 }
2468
2469 if (shift == s_end)
2470 {
2471 shift = s_start;
2472 sp++;
2473 dp++;
2474 }
2475 else
2476 shift += s_inc;
2477
2478 if (m == 1)
2479 m = 0x80;
2480 else
2481 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002482 }
2483 break;
2484 }
2485 case 2:
2486 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002487 png_bytep sp = png_ptr->row_buf + 1;
2488 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002489 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002490 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002491 int shift;
2492 png_uint_32 i;
2493 png_uint_32 row_width = png_ptr->width;
2494 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002495
Andreas Dilger47a0c421997-05-16 02:46:07 -05002496#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2497 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002498 {
2499 s_start = 0;
2500 s_end = 6;
2501 s_inc = 2;
2502 }
2503 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002504#endif
2505 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002506 s_start = 6;
2507 s_end = 0;
2508 s_inc = -2;
2509 }
2510
2511 shift = s_start;
2512
2513 for (i = 0; i < row_width; i++)
2514 {
2515 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002516 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002517 value = (*sp >> shift) & 0x03;
2518 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2519 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002520 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002521
2522 if (shift == s_end)
2523 {
2524 shift = s_start;
2525 sp++;
2526 dp++;
2527 }
2528 else
2529 shift += s_inc;
2530 if (m == 1)
2531 m = 0x80;
2532 else
2533 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002534 }
2535 break;
2536 }
2537 case 4:
2538 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002539 png_bytep sp = png_ptr->row_buf + 1;
2540 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002541 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002542 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002543 int shift;
2544 png_uint_32 i;
2545 png_uint_32 row_width = png_ptr->width;
2546 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002547
Andreas Dilger47a0c421997-05-16 02:46:07 -05002548#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2549 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002550 {
2551 s_start = 0;
2552 s_end = 4;
2553 s_inc = 4;
2554 }
2555 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002556#endif
2557 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002558 s_start = 4;
2559 s_end = 0;
2560 s_inc = -4;
2561 }
2562 shift = s_start;
2563
2564 for (i = 0; i < row_width; i++)
2565 {
2566 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002567 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002568 value = (*sp >> shift) & 0xf;
2569 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2570 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002571 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002572
2573 if (shift == s_end)
2574 {
2575 shift = s_start;
2576 sp++;
2577 dp++;
2578 }
2579 else
2580 shift += s_inc;
2581 if (m == 1)
2582 m = 0x80;
2583 else
2584 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002585 }
2586 break;
2587 }
2588 default:
2589 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002590 png_bytep sp = png_ptr->row_buf + 1;
2591 png_bytep dp = row;
2592 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2593 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002594 png_uint_32 row_width = png_ptr->width;
2595 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002596
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002597
2598 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002599 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002600 if (m & mask)
2601 {
2602 png_memcpy(dp, sp, pixel_bytes);
2603 }
2604
2605 sp += pixel_bytes;
2606 dp += pixel_bytes;
2607
2608 if (m == 1)
2609 m = 0x80;
2610 else
2611 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002612 }
2613 break;
2614 }
2615 }
2616 }
2617}
2618
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002619#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002620/* OLD pre-1.0.9 interface:
2621void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2622 png_uint_32 transformations)
2623 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002624void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002625png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002626{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002627 png_row_infop row_info = &(png_ptr->row_info);
2628 png_bytep row = png_ptr->row_buf + 1;
2629 int pass = png_ptr->pass;
2630 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002631#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002632 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002633 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002634 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002635#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002636
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002637 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002638 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002639 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002640 png_uint_32 final_width;
2641
2642 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002643
2644 switch (row_info->pixel_depth)
2645 {
2646 case 1:
2647 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002648 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2649 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002650 int sshift, dshift;
2651 int s_start, s_end, s_inc;
2652 int jstop = png_pass_inc[pass];
2653 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002654 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002655 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002656
Andreas Dilger47a0c421997-05-16 02:46:07 -05002657#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2658 if (transformations & PNG_PACKSWAP)
2659 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002660 sshift = (int)((row_info->width + 7) & 0x07);
2661 dshift = (int)((final_width + 7) & 0x07);
2662 s_start = 7;
2663 s_end = 0;
2664 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002665 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002666 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002667#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002668 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002669 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2670 dshift = 7 - (int)((final_width + 7) & 0x07);
2671 s_start = 0;
2672 s_end = 7;
2673 s_inc = 1;
2674 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002675
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002676 for (i = 0; i < row_info->width; i++)
2677 {
2678 v = (png_byte)((*sp >> sshift) & 0x01);
2679 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002680 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002681 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2682 *dp |= (png_byte)(v << dshift);
2683 if (dshift == s_end)
2684 {
2685 dshift = s_start;
2686 dp--;
2687 }
2688 else
2689 dshift += s_inc;
2690 }
2691 if (sshift == s_end)
2692 {
2693 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002694 sp--;
2695 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002696 else
2697 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002698 }
2699 break;
2700 }
2701 case 2:
2702 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002703 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2704 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2705 int sshift, dshift;
2706 int s_start, s_end, s_inc;
2707 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002708 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002709
Andreas Dilger47a0c421997-05-16 02:46:07 -05002710#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2711 if (transformations & PNG_PACKSWAP)
2712 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002713 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2714 dshift = (int)(((final_width + 3) & 0x03) << 1);
2715 s_start = 6;
2716 s_end = 0;
2717 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002718 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002719 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002720#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002721 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002722 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2723 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2724 s_start = 0;
2725 s_end = 6;
2726 s_inc = 2;
2727 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002728
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002729 for (i = 0; i < row_info->width; i++)
2730 {
2731 png_byte v;
2732 int j;
2733
2734 v = (png_byte)((*sp >> sshift) & 0x03);
2735 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002736 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002737 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2738 *dp |= (png_byte)(v << dshift);
2739 if (dshift == s_end)
2740 {
2741 dshift = s_start;
2742 dp--;
2743 }
2744 else
2745 dshift += s_inc;
2746 }
2747 if (sshift == s_end)
2748 {
2749 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002750 sp--;
2751 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002752 else
2753 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002754 }
2755 break;
2756 }
2757 case 4:
2758 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002759 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2760 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002761 int sshift, dshift;
2762 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002763 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002764 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002765
Andreas Dilger47a0c421997-05-16 02:46:07 -05002766#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2767 if (transformations & PNG_PACKSWAP)
2768 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002769 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2770 dshift = (int)(((final_width + 1) & 0x01) << 2);
2771 s_start = 4;
2772 s_end = 0;
2773 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002774 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002775 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002776#endif
2777 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002778 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2779 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2780 s_start = 0;
2781 s_end = 4;
2782 s_inc = 4;
2783 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002784
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002785 for (i = 0; i < row_info->width; i++)
2786 {
2787 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2788 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002789
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002790 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002791 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002792 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2793 *dp |= (png_byte)(v << dshift);
2794 if (dshift == s_end)
2795 {
2796 dshift = s_start;
2797 dp--;
2798 }
2799 else
2800 dshift += s_inc;
2801 }
2802 if (sshift == s_end)
2803 {
2804 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002805 sp--;
2806 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002807 else
2808 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002809 }
2810 break;
2811 }
2812 default:
2813 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002814 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
2815 png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002816 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002817
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002818 int jstop = png_pass_inc[pass];
2819 png_uint_32 i;
2820
2821 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002822 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002823 png_byte v[8];
2824 int j;
2825
2826 png_memcpy(v, sp, pixel_bytes);
2827 for (j = 0; j < jstop; j++)
2828 {
2829 png_memcpy(dp, v, pixel_bytes);
2830 dp -= pixel_bytes;
2831 }
2832 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002833 }
2834 break;
2835 }
2836 }
2837 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002838 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002839 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002840#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002841 transformations = transformations; /* silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002842#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002843}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002844#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002845
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002846void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002847png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002848 png_bytep prev_row, int filter)
2849{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002850 png_debug(1, "in png_read_filter_row");
2851 png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002852 switch (filter)
2853 {
2854 case PNG_FILTER_VALUE_NONE:
2855 break;
2856 case PNG_FILTER_VALUE_SUB:
2857 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002858 png_uint_32 i;
2859 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002860 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002861 png_bytep rp = row + bpp;
2862 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002863
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002864 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002865 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002866 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2867 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002868 }
2869 break;
2870 }
2871 case PNG_FILTER_VALUE_UP:
2872 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002873 png_uint_32 i;
2874 png_uint_32 istop = row_info->rowbytes;
2875 png_bytep rp = row;
2876 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002877
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002878 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002879 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002880 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2881 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002882 }
2883 break;
2884 }
2885 case PNG_FILTER_VALUE_AVG:
2886 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002887 png_uint_32 i;
2888 png_bytep rp = row;
2889 png_bytep pp = prev_row;
2890 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002891 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002892 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002893
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002894 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002895 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002896 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002897 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002898 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002899 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002900
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002901 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002902 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002903 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002904 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002905 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002906 }
2907 break;
2908 }
2909 case PNG_FILTER_VALUE_PAETH:
2910 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002911 png_uint_32 i;
2912 png_bytep rp = row;
2913 png_bytep pp = prev_row;
2914 png_bytep lp = row;
2915 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002916 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002917 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002918
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002919 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002920 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002921 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2922 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002923 }
2924
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002925 for (i = 0; i < istop; i++) /* use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002926 {
2927 int a, b, c, pa, pb, pc, p;
2928
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002929 a = *lp++;
2930 b = *pp++;
2931 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002932
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002933 p = b - c;
2934 pc = a - c;
2935
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002936#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002937 pa = abs(p);
2938 pb = abs(pc);
2939 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002940#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002941 pa = p < 0 ? -p : p;
2942 pb = pc < 0 ? -pc : pc;
2943 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002944#endif
2945
2946 /*
2947 if (pa <= pb && pa <= pc)
2948 p = a;
2949 else if (pb <= pc)
2950 p = b;
2951 else
2952 p = c;
2953 */
2954
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002955 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002956
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002957 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2958 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002959 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002960 break;
2961 }
2962 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002963 png_warning(png_ptr, "Ignoring bad adaptive filter type");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002964 *row = 0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002965 break;
2966 }
2967}
Guy Schalnat0d580581995-07-20 02:43:20 -05002968
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002969void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002970png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002971{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002972#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002973#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002974 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002975
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002976 /* start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002977 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002978
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002979 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002980 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002981
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002982 /* start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002983 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002984
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002985 /* offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002986 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
2987#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002988#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002989
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002990 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002991 png_ptr->row_number++;
2992 if (png_ptr->row_number < png_ptr->num_rows)
2993 return;
2994
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002995#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05002996 if (png_ptr->interlaced)
2997 {
2998 png_ptr->row_number = 0;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002999 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003000 do
3001 {
3002 png_ptr->pass++;
3003 if (png_ptr->pass >= 7)
3004 break;
3005 png_ptr->iwidth = (png_ptr->width +
3006 png_pass_inc[png_ptr->pass] - 1 -
3007 png_pass_start[png_ptr->pass]) /
3008 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003009
3010 png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
3011 png_ptr->iwidth) + 1;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003012
Guy Schalnat0d580581995-07-20 02:43:20 -05003013 if (!(png_ptr->transformations & PNG_INTERLACE))
3014 {
3015 png_ptr->num_rows = (png_ptr->height +
3016 png_pass_yinc[png_ptr->pass] - 1 -
3017 png_pass_ystart[png_ptr->pass]) /
3018 png_pass_yinc[png_ptr->pass];
3019 if (!(png_ptr->num_rows))
3020 continue;
3021 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003022 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003023 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05003024 } while (png_ptr->iwidth == 0);
3025
3026 if (png_ptr->pass < 7)
3027 return;
3028 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003029#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003030
Guy Schalnate5a37791996-06-05 15:50:50 -05003031 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003032 {
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003033#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003034 PNG_CONST PNG_IDAT;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003035#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003036 char extra;
3037 int ret;
3038
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003039 png_ptr->zstream.next_out = (Byte *)&extra;
3040 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003041 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003042 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003043 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003044 {
3045 while (!png_ptr->idat_size)
3046 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003047 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05003048
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003049 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003050
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003051 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003052 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05003053 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003054 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003055 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003056 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003057
3058 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003059 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3060 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05003061 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003062 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3063 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3064 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003065 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003066 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05003067 if (ret == Z_STREAM_END)
3068 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003069 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05003070 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003071 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003072 png_ptr->mode |= PNG_AFTER_IDAT;
3073 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003074 break;
3075 }
3076 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003077 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05003078 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003079
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003080 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003081 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003082 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003083 png_ptr->mode |= PNG_AFTER_IDAT;
3084 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3085 break;
3086 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003087
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003088 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003089 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003090 }
3091
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003092 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003093 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003094
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003095 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003096
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003097 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003098}
3099
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003100void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003101png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003102{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003103#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003104#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003105 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003106
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003107 /* start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003108 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003109
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003110 /* offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003111 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003112
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003113 /* start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003114 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003115
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06003116 /* offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003117 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3118#endif
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06003119#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003120
Guy Schalnat0d580581995-07-20 02:43:20 -05003121 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003122 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003123
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003124 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003125 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003126 png_init_read_transformations(png_ptr);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003127#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003128 if (png_ptr->interlaced)
3129 {
3130 if (!(png_ptr->transformations & PNG_INTERLACE))
3131 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
3132 png_pass_ystart[0]) / png_pass_yinc[0];
3133 else
3134 png_ptr->num_rows = png_ptr->height;
3135
3136 png_ptr->iwidth = (png_ptr->width +
3137 png_pass_inc[png_ptr->pass] - 1 -
3138 png_pass_start[png_ptr->pass]) /
3139 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003140
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003141 png_ptr->irowbytes =
3142 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05003143 }
3144 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003145#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003146 {
3147 png_ptr->num_rows = png_ptr->height;
3148 png_ptr->iwidth = png_ptr->width;
3149 png_ptr->irowbytes = png_ptr->rowbytes + 1;
3150 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003151 max_pixel_depth = png_ptr->pixel_depth;
3152
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003153#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003154 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003155 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003156#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003157
Guy Schalnate5a37791996-06-05 15:50:50 -05003158#if defined(PNG_READ_EXPAND_SUPPORTED)
3159 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003160 {
3161 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3162 {
3163 if (png_ptr->num_trans)
3164 max_pixel_depth = 32;
3165 else
3166 max_pixel_depth = 24;
3167 }
3168 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3169 {
3170 if (max_pixel_depth < 8)
3171 max_pixel_depth = 8;
3172 if (png_ptr->num_trans)
3173 max_pixel_depth *= 2;
3174 }
3175 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3176 {
3177 if (png_ptr->num_trans)
3178 {
3179 max_pixel_depth *= 4;
3180 max_pixel_depth /= 3;
3181 }
3182 }
3183 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003184#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003185
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003186#if defined(PNG_READ_FILLER_SUPPORTED)
3187 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003188 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003189 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3190 max_pixel_depth = 32;
3191 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003192 {
3193 if (max_pixel_depth <= 8)
3194 max_pixel_depth = 16;
3195 else
3196 max_pixel_depth = 32;
3197 }
3198 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3199 {
3200 if (max_pixel_depth <= 32)
3201 max_pixel_depth = 32;
3202 else
3203 max_pixel_depth = 64;
3204 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003205 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003206#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003207
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003208#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003209 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3210 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003211 if (
3212#if defined(PNG_READ_EXPAND_SUPPORTED)
3213 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
3214#endif
3215#if defined(PNG_READ_FILLER_SUPPORTED)
3216 (png_ptr->transformations & (PNG_FILLER)) ||
3217#endif
3218 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003219 {
3220 if (max_pixel_depth <= 16)
3221 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003222 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003223 max_pixel_depth = 64;
3224 }
3225 else
3226 {
3227 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003228 {
3229 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3230 max_pixel_depth = 32;
3231 else
3232 max_pixel_depth = 24;
3233 }
3234 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3235 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003236 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003237 max_pixel_depth = 48;
3238 }
3239 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003240#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003241
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003242#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3243defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003244 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003245 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003246 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003247 png_ptr->user_transform_channels;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003248 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003249 max_pixel_depth=user_pixel_depth;
3250 }
3251#endif
3252
Guy Schalnat0d580581995-07-20 02:43:20 -05003253 /* align the width on the next larger 8 pixels. Mainly used
3254 for interlacing */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003255 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Guy Schalnat0d580581995-07-20 02:43:20 -05003256 /* calculate the maximum bytes needed, adding a byte and a pixel
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003257 for safety's sake */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003258 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Guy Schalnat0d580581995-07-20 02:43:20 -05003259 1 + ((max_pixel_depth + 7) >> 3);
3260#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003261 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003262 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003263#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003264
3265 if (row_bytes + 64 > png_ptr->old_big_row_buf_size)
3266 {
3267 png_free(png_ptr, png_ptr->big_row_buf);
3268 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
3269 png_ptr->row_buf = png_ptr->big_row_buf+32;
3270 png_ptr->old_big_row_buf_size = row_bytes+64;
3271 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003272
3273#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003274 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003275 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003276#endif
Glenn Randers-Pehrsonebd7f9a2006-10-19 09:37:56 -05003277 if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003278 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003279
3280 if (png_ptr->rowbytes+1 > png_ptr->old_prev_row_size)
3281 {
3282 png_free(png_ptr, png_ptr->prev_row);
3283 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
3284 png_ptr->rowbytes + 1));
3285 png_ptr->old_prev_row_size = png_ptr->rowbytes+1;
3286 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003287
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003288 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003289
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003290 png_debug1(3, "width = %lu,", png_ptr->width);
3291 png_debug1(3, "height = %lu,", png_ptr->height);
3292 png_debug1(3, "iwidth = %lu,", png_ptr->iwidth);
3293 png_debug1(3, "num_rows = %lu,", png_ptr->num_rows);
3294 png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes);
3295 png_debug1(3, "irowbytes = %lu,", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05003296
Guy Schalnate5a37791996-06-05 15:50:50 -05003297 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003298}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003299#endif /* PNG_READ_SUPPORTED */