blob: 94b521c810f28ea17d079364d22da15b2656ffde [file] [log] [blame]
Andreas Dilger47a0c421997-05-16 02:46:07 -05001/* pngrutil.c - utilities to read a PNG file
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002 *
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003 * libpng version 1.2.6rc1 - August 4, 2004
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06004 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05005 * Copyright (c) 1998-2004 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06008 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05009 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060010 * libpng itself during the course of reading an image.
11 */
Guy Schalnat0d580581995-07-20 02:43:20 -050012
13#define PNG_INTERNAL
14#include "png.h"
15
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -050016#if defined(_WIN32_WCE)
17/* strtod() function is not supported on WindowsCE */
18# ifdef PNG_FLOATING_POINT_SUPPORTED
19__inline double strtod(const char *nptr, char **endptr)
20{
21 double result = 0;
22 int len;
23 wchar_t *str, *end;
24
25 len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
26 str = (wchar_t *)malloc(len * sizeof(wchar_t));
27 if ( NULL != str )
28 {
29 MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
30 result = wcstod(str, &end);
31 len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -050032 *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -050033 free(str);
34 }
35 return result;
36}
37# endif
38#endif
39
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050040png_uint_32 /* PRIVATE */
41png_get_uint_31(png_structp png_ptr, png_bytep buf)
42{
43 png_uint_32 i = png_get_uint_32(buf);
44 if (i > PNG_UINT_31_MAX)
45 png_error(png_ptr, "PNG unsigned integer out of range.\n");
46 return (i);
47}
Andreas Dilger47a0c421997-05-16 02:46:07 -050048#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050049/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050050png_uint_32 /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -060051png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050052{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050053 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
Guy Schalnat0d580581995-07-20 02:43:20 -050054 ((png_uint_32)(*(buf + 1)) << 16) +
55 ((png_uint_32)(*(buf + 2)) << 8) +
56 (png_uint_32)(*(buf + 3));
57
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060058 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050059}
60
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -060061#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050062/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050063 * data is stored in the PNG file in two's complement format, and it is
64 * assumed that the machine format for signed integers is the same. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050065png_int_32 /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -050066png_get_int_32(png_bytep buf)
67{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050068 png_int_32 i = ((png_int_32)(*buf) << 24) +
Andreas Dilger47a0c421997-05-16 02:46:07 -050069 ((png_int_32)(*(buf + 1)) << 16) +
70 ((png_int_32)(*(buf + 2)) << 8) +
71 (png_int_32)(*(buf + 3));
72
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060073 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050074}
75#endif /* PNG_READ_pCAL_SUPPORTED */
76
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050077/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050078png_uint_16 /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -060079png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050080{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050081 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060082 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050083
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060084 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050085}
Andreas Dilger47a0c421997-05-16 02:46:07 -050086#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050087
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060088/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050089void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -050090png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050091{
Guy Schalnat6d764711995-12-19 03:22:19 -060092 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -050093 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050094}
95
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060096/* Optionally skip data and then check the CRC. Depending on whether we
97 are reading a ancillary or critical chunk, and how the program has set
Andreas Dilger47a0c421997-05-16 02:46:07 -050098 things up, we may calculate the CRC on the data and print a message.
99 Returns '1' if there was a CRC error, '0' otherwise. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500100int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600101png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500102{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500103 png_size_t i;
104 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500105
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500106 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600107 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500108 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500109 }
110 if (i)
111 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500112 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500113 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600114
Andreas Dilger47a0c421997-05-16 02:46:07 -0500115 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600116 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600117 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600118 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
119 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600120 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600121 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600122 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600123 }
124 else
125 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600126 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600127 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600128 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600129 }
130
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600131 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500132}
133
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600134/* Compare the CRC stored in the PNG file with that calculated by libpng from
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600135 the data it has read thus far. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500136int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600137png_crc_error(png_structp png_ptr)
138{
139 png_byte crc_bytes[4];
140 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500141 int need_crc = 1;
142
143 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
144 {
145 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
146 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
147 need_crc = 0;
148 }
149 else /* critical */
150 {
151 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
152 need_crc = 0;
153 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600154
155 png_read_data(png_ptr, crc_bytes, 4);
156
Andreas Dilger47a0c421997-05-16 02:46:07 -0500157 if (need_crc)
158 {
159 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600160 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500161 }
162 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600163 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600164}
165
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600166#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500167 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600168/*
169 * Decompress trailing data in a chunk. The assumption is that chunkdata
170 * points at an allocated area holding the contents of a chunk with a
171 * trailing compressed part. What we get back is an allocated area
172 * holding the original prefix part and an uncompressed version of the
173 * trailing part (the malloc area passed in is freed).
174 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500175png_charp /* PRIVATE */
176png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600177 png_charp chunkdata, png_size_t chunklength,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600178 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600179{
180 static char msg[] = "Error decoding compressed text";
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500181 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600182 png_size_t text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600183
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600184 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600185 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500186 int ret = Z_OK;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600187 png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
188 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
189 png_ptr->zstream.next_out = png_ptr->zbuf;
190 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
191
192 text_size = 0;
193 text = NULL;
194
195 while (png_ptr->zstream.avail_in)
196 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500197 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600198 if (ret != Z_OK && ret != Z_STREAM_END)
199 {
200 if (png_ptr->zstream.msg != NULL)
201 png_warning(png_ptr, png_ptr->zstream.msg);
202 else
203 png_warning(png_ptr, msg);
204 inflateReset(&png_ptr->zstream);
205 png_ptr->zstream.avail_in = 0;
206
207 if (text == NULL)
208 {
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500209 text_size = prefix_size + png_sizeof(msg) + 1;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500210 text = (png_charp)png_malloc_warn(png_ptr, text_size);
211 if (text == NULL)
212 {
213 png_free(png_ptr,chunkdata);
214 png_error(png_ptr,"Not enough memory to decompress chunk");
215 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500216 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600217 }
218
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500219 text[text_size - 1] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600220
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500221 /* Copy what we can of the error message into the text chunk */
222 text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500223 text_size = png_sizeof(msg) > text_size ? text_size :
224 png_sizeof(msg);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500225 png_memcpy(text + prefix_size, msg, text_size + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600226 break;
227 }
228 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
229 {
230 if (text == NULL)
231 {
232 text_size = prefix_size +
233 png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500234 text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
235 if (text == NULL)
236 {
237 png_free(png_ptr,chunkdata);
238 png_error(png_ptr,"Not enough memory to decompress chunk.");
239 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500240 png_memcpy(text + prefix_size, png_ptr->zbuf,
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500241 text_size - prefix_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500242 png_memcpy(text, chunkdata, prefix_size);
243 *(text + text_size) = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600244 }
245 else
246 {
247 png_charp tmp;
248
249 tmp = text;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500250 text = (png_charp)png_malloc_warn(png_ptr,
251 (png_uint_32)(text_size +
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600252 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500253 if (text == NULL)
254 {
255 png_free(png_ptr, tmp);
256 png_free(png_ptr, chunkdata);
257 png_error(png_ptr,"Not enough memory to decompress chunk..");
258 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600259 png_memcpy(text, tmp, text_size);
260 png_free(png_ptr, tmp);
261 png_memcpy(text + text_size, png_ptr->zbuf,
262 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
263 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
264 *(text + text_size) = 0x00;
265 }
266 if (ret == Z_STREAM_END)
267 break;
268 else
269 {
270 png_ptr->zstream.next_out = png_ptr->zbuf;
271 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
272 }
273 }
274 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500275 if (ret != Z_STREAM_END)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500276 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500277#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500278 char umsg[50];
279
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500280 if (ret == Z_BUF_ERROR)
281 sprintf(umsg,"Buffer error in compressed datastream in %s chunk",
282 png_ptr->chunk_name);
283 else if (ret == Z_DATA_ERROR)
284 sprintf(umsg,"Data error in compressed datastream in %s chunk",
285 png_ptr->chunk_name);
286 else
287 sprintf(umsg,"Incomplete compressed datastream in %s chunk",
288 png_ptr->chunk_name);
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500289 png_warning(png_ptr, umsg);
290#else
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500291 png_warning(png_ptr,
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500292 "Incomplete compressed datastream in chunk other than IDAT");
293#endif
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600294 text_size=prefix_size;
295 if (text == NULL)
296 {
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -0500297 text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
298 if (text == NULL)
299 {
300 png_free(png_ptr, chunkdata);
301 png_error(png_ptr,"Not enough memory for text.");
302 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500303 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600304 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500305 *(text + text_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500306 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600307
308 inflateReset(&png_ptr->zstream);
309 png_ptr->zstream.avail_in = 0;
310
311 png_free(png_ptr, chunkdata);
312 chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600313 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600314 }
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600315 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600316 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500317#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600318 char umsg[50];
319
320 sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
321 png_warning(png_ptr, umsg);
322#else
323 png_warning(png_ptr, "Unknown zTXt compression type");
324#endif
325
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -0600326 *(chunkdata + prefix_size) = 0x00;
327 *newlength=prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600328 }
329
330 return chunkdata;
331}
332#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600333
Guy Schalnat0d580581995-07-20 02:43:20 -0500334/* read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500335void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600336png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500337{
338 png_byte buf[13];
339 png_uint_32 width, height;
340 int bit_depth, color_type, compression_type, filter_type;
341 int interlace_type;
342
Andreas Dilger47a0c421997-05-16 02:46:07 -0500343 png_debug(1, "in png_handle_IHDR\n");
344
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600345 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500346 png_error(png_ptr, "Out of place IHDR");
347
Guy Schalnat0d580581995-07-20 02:43:20 -0500348 /* check the length */
349 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600350 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500351
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600352 png_ptr->mode |= PNG_HAVE_IHDR;
353
Guy Schalnat0d580581995-07-20 02:43:20 -0500354 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600355 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500356
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500357 width = png_get_uint_31(png_ptr, buf);
358 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500359 bit_depth = buf[8];
360 color_type = buf[9];
361 compression_type = buf[10];
362 filter_type = buf[11];
363 interlace_type = buf[12];
364
Guy Schalnat0d580581995-07-20 02:43:20 -0500365 /* set internal variables */
366 png_ptr->width = width;
367 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600368 png_ptr->bit_depth = (png_byte)bit_depth;
369 png_ptr->interlaced = (png_byte)interlace_type;
370 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500371#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600372 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500373#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500374 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500375
376 /* find number of channels */
377 switch (png_ptr->color_type)
378 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500379 case PNG_COLOR_TYPE_GRAY:
380 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500381 png_ptr->channels = 1;
382 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500383 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 png_ptr->channels = 3;
385 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500386 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500387 png_ptr->channels = 2;
388 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500389 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500390 png_ptr->channels = 4;
391 break;
392 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600393
Guy Schalnat0d580581995-07-20 02:43:20 -0500394 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600395 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600396 png_ptr->channels);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500397 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500398 png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
399 png_debug1(3,"channels = %d\n", png_ptr->channels);
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -0500400 png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500401 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
402 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500403}
404
405/* read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500406void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600407png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500408{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600409 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600410 int num, i;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500411#ifndef PNG_NO_POINTER_INDEXING
412 png_colorp pal_ptr;
413#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500414
Andreas Dilger47a0c421997-05-16 02:46:07 -0500415 png_debug(1, "in png_handle_PLTE\n");
416
Guy Schalnate5a37791996-06-05 15:50:50 -0500417 if (!(png_ptr->mode & PNG_HAVE_IHDR))
418 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600419 else if (png_ptr->mode & PNG_HAVE_IDAT)
420 {
421 png_warning(png_ptr, "Invalid PLTE after IDAT");
422 png_crc_finish(png_ptr, length);
423 return;
424 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500425 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600426 png_error(png_ptr, "Duplicate PLTE chunk");
427
428 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500429
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500430 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
431 {
432 png_warning(png_ptr,
433 "Ignoring PLTE chunk in grayscale PNG");
434 png_crc_finish(png_ptr, length);
435 return;
436 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500437#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
438 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
439 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600440 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500441 return;
442 }
443#endif
444
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600445 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500446 {
447 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
448 {
449 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600450 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500451 return;
452 }
453 else
454 {
455 png_error(png_ptr, "Invalid palette chunk");
456 }
457 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500458
459 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500460
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500461#ifndef PNG_NO_POINTER_INDEXING
462 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
463 {
464 png_byte buf[3];
465
466 png_crc_read(png_ptr, buf, 3);
467 pal_ptr->red = buf[0];
468 pal_ptr->green = buf[1];
469 pal_ptr->blue = buf[2];
470 }
471#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600472 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500473 {
474 png_byte buf[3];
475
476 png_crc_read(png_ptr, buf, 3);
477 /* don't depend upon png_color being any order */
478 palette[i].red = buf[0];
479 palette[i].green = buf[1];
480 palette[i].blue = buf[2];
481 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500482#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600483
484 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
485 whatever the normal CRC configuration tells us. However, if we
486 have an RGB image, the PLTE can be considered ancillary, so
487 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600488#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600489 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600490#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600491 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500492 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600493 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600494#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600495 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
496 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600497 /* If we don't want to use the data from an ancillary chunk,
498 we have two options: an error abort, or a warning and we
499 ignore the data in this chunk (which should be OK, since
500 it's considered ancillary for a RGB or RGBA image). */
501 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
502 {
503 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
504 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600505 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600506 }
507 else
508 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600509 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600510 return;
511 }
512 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500513 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600514 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
515 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600516 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600517 }
518 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600519#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500520
Andreas Dilger47a0c421997-05-16 02:46:07 -0500521 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500522
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500523#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500524 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
525 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600526 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500527 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500528 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500529 {
530 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500531 png_ptr->num_trans = (png_uint_16)num;
532 }
533 if (info_ptr->num_trans > (png_uint_16)num)
534 {
535 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
536 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500537 }
538 }
539 }
540#endif
541
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600542}
Guy Schalnate5a37791996-06-05 15:50:50 -0500543
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500544void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600545png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
546{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500547 png_debug(1, "in png_handle_IEND\n");
548
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600549 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
550 {
551 png_error(png_ptr, "No image in file");
552 }
553
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600554 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600555
556 if (length != 0)
557 {
558 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600559 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500560 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500561
562 if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */
563 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500564}
565
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500566#if defined(PNG_READ_gAMA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500567void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600568png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500569{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600570 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600571#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500572 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600573#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500574 png_byte buf[4];
575
Andreas Dilger47a0c421997-05-16 02:46:07 -0500576 png_debug(1, "in png_handle_gAMA\n");
577
Guy Schalnate5a37791996-06-05 15:50:50 -0500578 if (!(png_ptr->mode & PNG_HAVE_IHDR))
579 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600580 else if (png_ptr->mode & PNG_HAVE_IDAT)
581 {
582 png_warning(png_ptr, "Invalid gAMA after IDAT");
583 png_crc_finish(png_ptr, length);
584 return;
585 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500586 else if (png_ptr->mode & PNG_HAVE_PLTE)
587 /* Should be an error, but we can cope with it */
588 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600589
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500590 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600591#if defined(PNG_READ_sRGB_SUPPORTED)
592 && !(info_ptr->valid & PNG_INFO_sRGB)
593#endif
594 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600595 {
596 png_warning(png_ptr, "Duplicate gAMA chunk");
597 png_crc_finish(png_ptr, length);
598 return;
599 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500600
Guy Schalnat0d580581995-07-20 02:43:20 -0500601 if (length != 4)
602 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600603 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600604 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500605 return;
606 }
607
608 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600609 if (png_crc_finish(png_ptr, 0))
610 return;
611
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600612 igamma = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500613 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500614 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500615 {
616 png_warning(png_ptr,
617 "Ignoring gAMA chunk with gamma=0");
618 return;
619 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500620
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600621#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600622 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600623 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600624 {
625 png_warning(png_ptr,
626 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500627#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600628 fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600629#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600630 return;
631 }
632#endif /* PNG_READ_sRGB_SUPPORTED */
633
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600634#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600635 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600636# ifdef PNG_READ_GAMMA_SUPPORTED
637 png_ptr->gamma = file_gamma;
638# endif
639 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600640#endif
641#ifdef PNG_FIXED_POINT_SUPPORTED
642 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
643#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500644}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500645#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500646
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500647#if defined(PNG_READ_sBIT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500648void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600649png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500650{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500651 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600652 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600653
Andreas Dilger47a0c421997-05-16 02:46:07 -0500654 png_debug(1, "in png_handle_sBIT\n");
655
Guy Schalnat69b14481996-01-10 02:56:49 -0600656 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500657
Guy Schalnate5a37791996-06-05 15:50:50 -0500658 if (!(png_ptr->mode & PNG_HAVE_IHDR))
659 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600660 else if (png_ptr->mode & PNG_HAVE_IDAT)
661 {
662 png_warning(png_ptr, "Invalid sBIT after IDAT");
663 png_crc_finish(png_ptr, length);
664 return;
665 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500666 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600667 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500668 /* Should be an error, but we can cope with it */
669 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600670 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500671 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600672 {
673 png_warning(png_ptr, "Duplicate sBIT chunk");
674 png_crc_finish(png_ptr, length);
675 return;
676 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500677
Guy Schalnat0d580581995-07-20 02:43:20 -0500678 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600679 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500680 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500681 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500682
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500683 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500684 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600685 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600686 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600687 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500688 }
689
Andreas Dilger47a0c421997-05-16 02:46:07 -0500690 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600691 if (png_crc_finish(png_ptr, 0))
692 return;
693
Guy Schalnat0d580581995-07-20 02:43:20 -0500694 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
695 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600696 png_ptr->sig_bit.red = buf[0];
697 png_ptr->sig_bit.green = buf[1];
698 png_ptr->sig_bit.blue = buf[2];
699 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500700 }
701 else
702 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600703 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600704 png_ptr->sig_bit.red = buf[0];
705 png_ptr->sig_bit.green = buf[0];
706 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600707 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500708 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500709 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500710}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500711#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500712
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500713#if defined(PNG_READ_cHRM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500714void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600715png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500716{
717 png_byte buf[4];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600718#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500719 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 -0600720#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600721 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 -0600722 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500723
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600724 png_uint_32 uint_x, uint_y;
725
Andreas Dilger47a0c421997-05-16 02:46:07 -0500726 png_debug(1, "in png_handle_cHRM\n");
727
Guy Schalnate5a37791996-06-05 15:50:50 -0500728 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600729 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600730 else if (png_ptr->mode & PNG_HAVE_IDAT)
731 {
732 png_warning(png_ptr, "Invalid cHRM after IDAT");
733 png_crc_finish(png_ptr, length);
734 return;
735 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500736 else if (png_ptr->mode & PNG_HAVE_PLTE)
737 /* Should be an error, but we can cope with it */
738 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600739
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500740 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600741#if defined(PNG_READ_sRGB_SUPPORTED)
742 && !(info_ptr->valid & PNG_INFO_sRGB)
743#endif
744 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600745 {
746 png_warning(png_ptr, "Duplicate cHRM chunk");
747 png_crc_finish(png_ptr, length);
748 return;
749 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500750
Guy Schalnat0d580581995-07-20 02:43:20 -0500751 if (length != 32)
752 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600753 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600754 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600755 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500756 }
757
758 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600759 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500760
761 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600762 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600763
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600764 if (uint_x > 80000L || uint_y > 80000L ||
765 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600766 {
767 png_warning(png_ptr, "Invalid cHRM white point");
768 png_crc_finish(png_ptr, 24);
769 return;
770 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600771 int_x_white = (png_fixed_point)uint_x;
772 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500773
774 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600775 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500776
777 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600778 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600779
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600780 if (uint_x > 80000L || uint_y > 80000L ||
781 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600782 {
783 png_warning(png_ptr, "Invalid cHRM red point");
784 png_crc_finish(png_ptr, 16);
785 return;
786 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600787 int_x_red = (png_fixed_point)uint_x;
788 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500789
790 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600791 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500792
793 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600794 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600795
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600796 if (uint_x > 80000L || uint_y > 80000L ||
797 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600798 {
799 png_warning(png_ptr, "Invalid cHRM green point");
800 png_crc_finish(png_ptr, 8);
801 return;
802 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600803 int_x_green = (png_fixed_point)uint_x;
804 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500805
806 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600807 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500808
809 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600810 uint_y = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500811
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600812 if (uint_x > 80000L || uint_y > 80000L ||
813 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600814 {
815 png_warning(png_ptr, "Invalid cHRM blue point");
816 png_crc_finish(png_ptr, 0);
817 return;
818 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600819 int_x_blue = (png_fixed_point)uint_x;
820 int_y_blue = (png_fixed_point)uint_y;
821
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600822#ifdef PNG_FLOATING_POINT_SUPPORTED
823 white_x = (float)int_x_white / (float)100000.0;
824 white_y = (float)int_y_white / (float)100000.0;
825 red_x = (float)int_x_red / (float)100000.0;
826 red_y = (float)int_y_red / (float)100000.0;
827 green_x = (float)int_x_green / (float)100000.0;
828 green_y = (float)int_y_green / (float)100000.0;
829 blue_x = (float)int_x_blue / (float)100000.0;
830 blue_y = (float)int_y_blue / (float)100000.0;
831#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600832
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600833#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600834 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600835 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600836 if (abs(int_x_white - 31270L) > 1000 ||
837 abs(int_y_white - 32900L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500838 abs(int_x_red - 64000L) > 1000 ||
839 abs(int_y_red - 33000L) > 1000 ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600840 abs(int_x_green - 30000L) > 1000 ||
841 abs(int_y_green - 60000L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500842 abs(int_x_blue - 15000L) > 1000 ||
843 abs(int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600844 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600845
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600846 png_warning(png_ptr,
847 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500848#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600849#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600850 fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
851 white_x, white_y, red_x, red_y);
852 fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
853 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600854#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600855 fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600856 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600857 fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600858 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600859#endif
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500860#endif /* PNG_NO_CONSOLE_IO */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600861 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600862 png_crc_finish(png_ptr, 0);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600863 return;
864 }
865#endif /* PNG_READ_sRGB_SUPPORTED */
866
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600867#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500868 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600869 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600870#endif
871#ifdef PNG_FIXED_POINT_SUPPORTED
872 png_set_cHRM_fixed(png_ptr, info_ptr,
873 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
874 int_y_green, int_x_blue, int_y_blue);
875#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600876 if (png_crc_finish(png_ptr, 0))
877 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500878}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500879#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500880
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600881#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500882void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600883png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
884{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600885 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600886 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600887
888 png_debug(1, "in png_handle_sRGB\n");
889
890 if (!(png_ptr->mode & PNG_HAVE_IHDR))
891 png_error(png_ptr, "Missing IHDR before sRGB");
892 else if (png_ptr->mode & PNG_HAVE_IDAT)
893 {
894 png_warning(png_ptr, "Invalid sRGB after IDAT");
895 png_crc_finish(png_ptr, length);
896 return;
897 }
898 else if (png_ptr->mode & PNG_HAVE_PLTE)
899 /* Should be an error, but we can cope with it */
900 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600901
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500902 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600903 {
904 png_warning(png_ptr, "Duplicate sRGB chunk");
905 png_crc_finish(png_ptr, length);
906 return;
907 }
908
909 if (length != 1)
910 {
911 png_warning(png_ptr, "Incorrect sRGB chunk length");
912 png_crc_finish(png_ptr, length);
913 return;
914 }
915
916 png_crc_read(png_ptr, buf, 1);
917 if (png_crc_finish(png_ptr, 0))
918 return;
919
920 intent = buf[0];
921 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600922 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600923 {
924 png_warning(png_ptr, "Unknown sRGB intent");
925 return;
926 }
927
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600928#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600929 if ((info_ptr->valid & PNG_INFO_gAMA))
930 {
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500931 png_fixed_point igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600932#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500933 igamma=info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600934#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600935# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500936 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600937# endif
938#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600939 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600940 {
941 png_warning(png_ptr,
942 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500943#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600944# ifdef PNG_FIXED_POINT_SUPPORTED
945 fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
946# else
947# ifdef PNG_FLOATING_POINT_SUPPORTED
948 fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
949# endif
950# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600951#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600952 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600953 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600954#endif /* PNG_READ_gAMA_SUPPORTED */
955
956#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500957#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600958 if (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600959 if (abs(info_ptr->int_x_white - 31270L) > 1000 ||
960 abs(info_ptr->int_y_white - 32900L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500961 abs(info_ptr->int_x_red - 64000L) > 1000 ||
962 abs(info_ptr->int_y_red - 33000L) > 1000 ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600963 abs(info_ptr->int_x_green - 30000L) > 1000 ||
964 abs(info_ptr->int_y_green - 60000L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500965 abs(info_ptr->int_x_blue - 15000L) > 1000 ||
966 abs(info_ptr->int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600967 {
968 png_warning(png_ptr,
969 "Ignoring incorrect cHRM value when sRGB is also present");
970 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500971#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600972#endif /* PNG_READ_cHRM_SUPPORTED */
973
974 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
975}
976#endif /* PNG_READ_sRGB_SUPPORTED */
977
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600978#if defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500979void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600980png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
981/* Note: this does not properly handle chunks that are > 64K under DOS */
982{
983 png_charp chunkdata;
984 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600985 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600986 png_charp profile;
987 png_uint_32 skip = 0;
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500988 png_uint_32 profile_size, profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600989 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600990
991 png_debug(1, "in png_handle_iCCP\n");
992
993 if (!(png_ptr->mode & PNG_HAVE_IHDR))
994 png_error(png_ptr, "Missing IHDR before iCCP");
995 else if (png_ptr->mode & PNG_HAVE_IDAT)
996 {
997 png_warning(png_ptr, "Invalid iCCP after IDAT");
998 png_crc_finish(png_ptr, length);
999 return;
1000 }
1001 else if (png_ptr->mode & PNG_HAVE_PLTE)
1002 /* Should be an error, but we can cope with it */
1003 png_warning(png_ptr, "Out of place iCCP chunk");
1004
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001005 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001006 {
1007 png_warning(png_ptr, "Duplicate iCCP chunk");
1008 png_crc_finish(png_ptr, length);
1009 return;
1010 }
1011
1012#ifdef PNG_MAX_MALLOC_64K
1013 if (length > (png_uint_32)65535L)
1014 {
1015 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1016 skip = length - (png_uint_32)65535L;
1017 length = (png_uint_32)65535L;
1018 }
1019#endif
1020
1021 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
1022 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001023 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001024
1025 if (png_crc_finish(png_ptr, skip))
1026 {
1027 png_free(png_ptr, chunkdata);
1028 return;
1029 }
1030
1031 chunkdata[slength] = 0x00;
1032
1033 for (profile = chunkdata; *profile; profile++)
1034 /* empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001035
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001036 ++profile;
1037
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001038 /* there should be at least one zero (the compression type byte)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001039 following the separator, and we should be on it */
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001040 if ( profile >= chunkdata + slength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001041 {
1042 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001043 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001044 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001045 }
1046
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001047 /* compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001048 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001049 if (compression_type)
1050 {
1051 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
1052 compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
1053 wrote nonzero) */
1054 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001055
1056 prefix_length = profile - chunkdata;
1057 chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001058 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001059
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001060 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001061
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001062 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001063 {
1064 png_free(png_ptr, chunkdata);
1065 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1066 return;
1067 }
1068
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001069 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001070 pC = (png_bytep)(chunkdata+prefix_length);
1071 profile_size = ((*(pC ))<<24) |
1072 ((*(pC+1))<<16) |
1073 ((*(pC+2))<< 8) |
1074 ((*(pC+3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001075
1076 if(profile_size < profile_length)
1077 profile_length = profile_size;
1078
1079 if(profile_size > profile_length)
1080 {
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001081 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001082 png_warning(png_ptr, "Ignoring truncated iCCP profile.\n");
1083 return;
1084 }
1085
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001086 png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001087 chunkdata + prefix_length, profile_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001088 png_free(png_ptr, chunkdata);
1089}
1090#endif /* PNG_READ_iCCP_SUPPORTED */
1091
1092#if defined(PNG_READ_sPLT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001093void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001094png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1095/* Note: this does not properly handle chunks that are > 64K under DOS */
1096{
1097 png_bytep chunkdata;
1098 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001099 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001100#ifdef PNG_NO_POINTER_INDEXING
1101 png_sPLT_entryp pp;
1102#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001103 int data_length, entry_size, i;
1104 png_uint_32 skip = 0;
1105 png_size_t slength;
1106
1107 png_debug(1, "in png_handle_sPLT\n");
1108
1109 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1110 png_error(png_ptr, "Missing IHDR before sPLT");
1111 else if (png_ptr->mode & PNG_HAVE_IDAT)
1112 {
1113 png_warning(png_ptr, "Invalid sPLT after IDAT");
1114 png_crc_finish(png_ptr, length);
1115 return;
1116 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001117
1118#ifdef PNG_MAX_MALLOC_64K
1119 if (length > (png_uint_32)65535L)
1120 {
1121 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1122 skip = length - (png_uint_32)65535L;
1123 length = (png_uint_32)65535L;
1124 }
1125#endif
1126
1127 chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001128 slength = (png_size_t)length;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001129 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001130
1131 if (png_crc_finish(png_ptr, skip))
1132 {
1133 png_free(png_ptr, chunkdata);
1134 return;
1135 }
1136
1137 chunkdata[slength] = 0x00;
1138
1139 for (entry_start = chunkdata; *entry_start; entry_start++)
1140 /* empty loop to find end of name */ ;
1141 ++entry_start;
1142
1143 /* a sample depth should follow the separator, and we should be on it */
1144 if (entry_start > chunkdata + slength)
1145 {
1146 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001147 png_warning(png_ptr, "malformed sPLT chunk");
1148 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001149 }
1150
1151 new_palette.depth = *entry_start++;
1152 entry_size = (new_palette.depth == 8 ? 6 : 10);
1153 data_length = (slength - (entry_start - chunkdata));
1154
1155 /* integrity-check the data length */
1156 if (data_length % entry_size)
1157 {
1158 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001159 png_warning(png_ptr, "sPLT chunk has bad length");
1160 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001161 }
1162
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001163 new_palette.nentries = (png_uint_32) (data_length / entry_size);
1164 if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX /
1165 png_sizeof(png_sPLT_entry)))
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001166 {
1167 png_warning(png_ptr, "sPLT chunk too long");
1168 return;
1169 }
1170 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
1171 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
1172 if (new_palette.entries == NULL)
1173 {
1174 png_warning(png_ptr, "sPLT chunk requires too much memory");
1175 return;
1176 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001177
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001178#ifndef PNG_NO_POINTER_INDEXING
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001179 for (i = 0; i < new_palette.nentries; i++)
1180 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001181 png_sPLT_entryp pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001182
1183 if (new_palette.depth == 8)
1184 {
1185 pp->red = *entry_start++;
1186 pp->green = *entry_start++;
1187 pp->blue = *entry_start++;
1188 pp->alpha = *entry_start++;
1189 }
1190 else
1191 {
1192 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1193 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1194 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1195 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1196 }
1197 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1198 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001199#else
1200 pp = new_palette.entries;
1201 for (i = 0; i < new_palette.nentries; i++)
1202 {
1203
1204 if (new_palette.depth == 8)
1205 {
1206 pp[i].red = *entry_start++;
1207 pp[i].green = *entry_start++;
1208 pp[i].blue = *entry_start++;
1209 pp[i].alpha = *entry_start++;
1210 }
1211 else
1212 {
1213 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1214 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1215 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1216 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1217 }
1218 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1219 }
1220#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001221
1222 /* discard all chunk data except the name and stash that */
1223 new_palette.name = (png_charp)chunkdata;
1224
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001225 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001226
1227 png_free(png_ptr, chunkdata);
1228 png_free(png_ptr, new_palette.entries);
1229}
1230#endif /* PNG_READ_sPLT_SUPPORTED */
1231
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001232#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001233void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001234png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001235{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001236 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001237
Andreas Dilger47a0c421997-05-16 02:46:07 -05001238 png_debug(1, "in png_handle_tRNS\n");
1239
Guy Schalnate5a37791996-06-05 15:50:50 -05001240 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1241 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001242 else if (png_ptr->mode & PNG_HAVE_IDAT)
1243 {
1244 png_warning(png_ptr, "Invalid tRNS after IDAT");
1245 png_crc_finish(png_ptr, length);
1246 return;
1247 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001248 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001249 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001250 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001251 png_crc_finish(png_ptr, length);
1252 return;
1253 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001254
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001255 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001256 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001257 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001258
1259 if (length != 2)
1260 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001261 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001262 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001263 return;
1264 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001265
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001266 png_crc_read(png_ptr, buf, 2);
1267 png_ptr->num_trans = 1;
1268 png_ptr->trans_values.gray = png_get_uint_16(buf);
1269 }
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001270 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1271 {
1272 png_byte buf[6];
1273
1274 if (length != 6)
1275 {
1276 png_warning(png_ptr, "Incorrect tRNS chunk length");
1277 png_crc_finish(png_ptr, length);
1278 return;
1279 }
1280 png_crc_read(png_ptr, buf, (png_size_t)length);
1281 png_ptr->num_trans = 1;
1282 png_ptr->trans_values.red = png_get_uint_16(buf);
1283 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1284 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1285 }
1286 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1287 {
1288 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1289 {
1290 /* Should be an error, but we can cope with it. */
1291 png_warning(png_ptr, "Missing PLTE before tRNS");
1292 }
1293 if (length > (png_uint_32)png_ptr->num_palette ||
1294 length > PNG_MAX_PALETTE_LENGTH)
1295 {
1296 png_warning(png_ptr, "Incorrect tRNS chunk length");
1297 png_crc_finish(png_ptr, length);
1298 return;
1299 }
1300 if (length == 0)
1301 {
1302 png_warning(png_ptr, "Zero length tRNS chunk");
1303 png_crc_finish(png_ptr, length);
1304 return;
1305 }
1306 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1307 png_ptr->num_trans = (png_uint_16)length;
1308 }
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001309 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001310 {
1311 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001312 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001313 return;
1314 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001315
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001316 if (png_crc_finish(png_ptr, 0))
1317 return;
1318
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001319 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -05001320 &(png_ptr->trans_values));
1321}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001322#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001323
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001324#if defined(PNG_READ_bKGD_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001325void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001326png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001327{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001328 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001329 png_byte buf[6];
1330
Andreas Dilger47a0c421997-05-16 02:46:07 -05001331 png_debug(1, "in png_handle_bKGD\n");
1332
Guy Schalnate5a37791996-06-05 15:50:50 -05001333 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1334 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001335 else if (png_ptr->mode & PNG_HAVE_IDAT)
1336 {
1337 png_warning(png_ptr, "Invalid bKGD after IDAT");
1338 png_crc_finish(png_ptr, length);
1339 return;
1340 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001341 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1342 !(png_ptr->mode & PNG_HAVE_PLTE))
1343 {
1344 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001345 png_crc_finish(png_ptr, length);
1346 return;
1347 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001348 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001349 {
1350 png_warning(png_ptr, "Duplicate bKGD chunk");
1351 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001352 return;
1353 }
1354
Guy Schalnat0d580581995-07-20 02:43:20 -05001355 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1356 truelen = 1;
1357 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1358 truelen = 6;
1359 else
1360 truelen = 2;
1361
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001362 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001363 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001364 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001365 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001366 return;
1367 }
1368
Andreas Dilger47a0c421997-05-16 02:46:07 -05001369 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001370 if (png_crc_finish(png_ptr, 0))
1371 return;
1372
Guy Schalnate5a37791996-06-05 15:50:50 -05001373 /* We convert the index value into RGB components so that we can allow
1374 * arbitrary RGB values for background when we have transparency, and
1375 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001376 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001377 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001378 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001379 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001380 if(info_ptr->num_palette)
1381 {
1382 if(buf[0] > info_ptr->num_palette)
1383 {
1384 png_warning(png_ptr, "Incorrect bKGD chunk index value");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001385 return;
1386 }
1387 png_ptr->background.red =
1388 (png_uint_16)png_ptr->palette[buf[0]].red;
1389 png_ptr->background.green =
1390 (png_uint_16)png_ptr->palette[buf[0]].green;
1391 png_ptr->background.blue =
1392 (png_uint_16)png_ptr->palette[buf[0]].blue;
1393 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001394 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001395 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001396 {
1397 png_ptr->background.red =
1398 png_ptr->background.green =
1399 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001400 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001401 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001402 else
1403 {
1404 png_ptr->background.red = png_get_uint_16(buf);
1405 png_ptr->background.green = png_get_uint_16(buf + 2);
1406 png_ptr->background.blue = png_get_uint_16(buf + 4);
1407 }
1408
Andreas Dilger47a0c421997-05-16 02:46:07 -05001409 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001410}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001411#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001412
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001413#if defined(PNG_READ_hIST_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001414void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001415png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001416{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001417 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001418 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001419
Andreas Dilger47a0c421997-05-16 02:46:07 -05001420 png_debug(1, "in png_handle_hIST\n");
1421
Guy Schalnate5a37791996-06-05 15:50:50 -05001422 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1423 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001424 else if (png_ptr->mode & PNG_HAVE_IDAT)
1425 {
1426 png_warning(png_ptr, "Invalid hIST after IDAT");
1427 png_crc_finish(png_ptr, length);
1428 return;
1429 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001430 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1431 {
1432 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001433 png_crc_finish(png_ptr, length);
1434 return;
1435 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001436 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001437 {
1438 png_warning(png_ptr, "Duplicate hIST chunk");
1439 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001440 return;
1441 }
1442
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001443 num = length / 2 ;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001444 if (num != (unsigned int) png_ptr->num_palette || num >
1445 (unsigned int) PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001446 {
1447 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001448 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001449 return;
1450 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001451
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001452 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001453 {
1454 png_byte buf[2];
1455
1456 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001457 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001458 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001459
1460 if (png_crc_finish(png_ptr, 0))
1461 return;
1462
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001463 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001464}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001465#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001466
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001467#if defined(PNG_READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001468void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001469png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001470{
1471 png_byte buf[9];
1472 png_uint_32 res_x, res_y;
1473 int unit_type;
1474
Andreas Dilger47a0c421997-05-16 02:46:07 -05001475 png_debug(1, "in png_handle_pHYs\n");
1476
Guy Schalnate5a37791996-06-05 15:50:50 -05001477 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001478 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001479 else if (png_ptr->mode & PNG_HAVE_IDAT)
1480 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001481 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001482 png_crc_finish(png_ptr, length);
1483 return;
1484 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001485 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001486 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001487 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001488 png_crc_finish(png_ptr, length);
1489 return;
1490 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001491
Guy Schalnat0d580581995-07-20 02:43:20 -05001492 if (length != 9)
1493 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001494 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001495 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001496 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001497 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001498
1499 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001500 if (png_crc_finish(png_ptr, 0))
1501 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001502
1503 res_x = png_get_uint_32(buf);
1504 res_y = png_get_uint_32(buf + 4);
1505 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001506 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
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_oFFs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001511void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001512png_handle_oFFs(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];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001515 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001516 int unit_type;
1517
Andreas Dilger47a0c421997-05-16 02:46:07 -05001518 png_debug(1, "in png_handle_oFFs\n");
1519
Guy Schalnate5a37791996-06-05 15:50:50 -05001520 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1521 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001522 else if (png_ptr->mode & PNG_HAVE_IDAT)
1523 {
1524 png_warning(png_ptr, "Invalid oFFs after IDAT");
1525 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_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001529 {
1530 png_warning(png_ptr, "Duplicate oFFs chunk");
1531 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 oFFs 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;
1540 }
1541
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001542 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
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001546 offset_x = png_get_int_32(buf);
1547 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001548 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001549 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1550}
1551#endif
1552
1553#if defined(PNG_READ_pCAL_SUPPORTED)
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001554/* read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001555void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001556png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1557{
1558 png_charp purpose;
1559 png_int_32 X0, X1;
1560 png_byte type, nparams;
1561 png_charp buf, units, endptr;
1562 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001563 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001564 int i;
1565
1566 png_debug(1, "in png_handle_pCAL\n");
1567
1568 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1569 png_error(png_ptr, "Missing IHDR before pCAL");
1570 else if (png_ptr->mode & PNG_HAVE_IDAT)
1571 {
1572 png_warning(png_ptr, "Invalid pCAL after IDAT");
1573 png_crc_finish(png_ptr, length);
1574 return;
1575 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001576 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001577 {
1578 png_warning(png_ptr, "Duplicate pCAL chunk");
1579 png_crc_finish(png_ptr, length);
1580 return;
1581 }
1582
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001583 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
Andreas Dilger47a0c421997-05-16 02:46:07 -05001584 length + 1);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001585 purpose = (png_charp)png_malloc_warn(png_ptr, length + 1);
1586 if (purpose == NULL)
1587 {
1588 png_warning(png_ptr, "No memory for pCAL purpose.");
1589 return;
1590 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001591 slength = (png_size_t)length;
1592 png_crc_read(png_ptr, (png_bytep)purpose, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001593
1594 if (png_crc_finish(png_ptr, 0))
1595 {
1596 png_free(png_ptr, purpose);
1597 return;
1598 }
1599
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001600 purpose[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001601
1602 png_debug(3, "Finding end of pCAL purpose string\n");
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001603 for (buf = purpose; *buf; buf++)
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001604 /* empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001605
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001606 endptr = purpose + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001607
1608 /* We need to have at least 12 bytes after the purpose string
1609 in order to get the parameter information. */
1610 if (endptr <= buf + 12)
1611 {
1612 png_warning(png_ptr, "Invalid pCAL data");
1613 png_free(png_ptr, purpose);
1614 return;
1615 }
1616
1617 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1618 X0 = png_get_int_32((png_bytep)buf+1);
1619 X1 = png_get_int_32((png_bytep)buf+5);
1620 type = buf[9];
1621 nparams = buf[10];
1622 units = buf + 11;
1623
1624 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1625 /* Check that we have the right number of parameters for known
1626 equation types. */
1627 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1628 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1629 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1630 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1631 {
1632 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
1633 png_free(png_ptr, purpose);
1634 return;
1635 }
1636 else if (type >= PNG_EQUATION_LAST)
1637 {
1638 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1639 }
1640
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001641 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001642 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643
1644 png_debug(3, "Allocating pCAL parameters array\n");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001645 params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001646 *png_sizeof(png_charp))) ;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001647 if (params == NULL)
1648 {
1649 png_free(png_ptr, purpose);
1650 png_warning(png_ptr, "No memory for pCAL params.");
1651 return;
1652 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001653
1654 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001655 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001656 {
1657 buf++; /* Skip the null string terminator from previous parameter. */
1658
1659 png_debug1(3, "Reading pCAL parameter %d\n", i);
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001660 for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001661 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001662
1663 /* Make sure we haven't run out of data yet */
1664 if (buf > endptr)
1665 {
1666 png_warning(png_ptr, "Invalid pCAL data");
1667 png_free(png_ptr, purpose);
1668 png_free(png_ptr, params);
1669 return;
1670 }
1671 }
1672
1673 png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
1674 units, params);
1675
1676 png_free(png_ptr, purpose);
1677 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001678}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001679#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001680
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001681#if defined(PNG_READ_sCAL_SUPPORTED)
1682/* read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001683void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001684png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1685{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001686 png_charp buffer, ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001687#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001688 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001689 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001690#else
1691#ifdef PNG_FIXED_POINT_SUPPORTED
1692 png_charp swidth, sheight;
1693#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001694#endif
1695 png_size_t slength;
1696
1697 png_debug(1, "in png_handle_sCAL\n");
1698
1699 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1700 png_error(png_ptr, "Missing IHDR before sCAL");
1701 else if (png_ptr->mode & PNG_HAVE_IDAT)
1702 {
1703 png_warning(png_ptr, "Invalid sCAL after IDAT");
1704 png_crc_finish(png_ptr, length);
1705 return;
1706 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001707 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001708 {
1709 png_warning(png_ptr, "Duplicate sCAL chunk");
1710 png_crc_finish(png_ptr, length);
1711 return;
1712 }
1713
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001714 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001715 length + 1);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001716 buffer = (png_charp)png_malloc_warn(png_ptr, length + 1);
1717 if (buffer == NULL)
1718 {
1719 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
1720 return;
1721 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001722 slength = (png_size_t)length;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001723 png_crc_read(png_ptr, (png_bytep)buffer, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001724
1725 if (png_crc_finish(png_ptr, 0))
1726 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001727 png_free(png_ptr, buffer);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001728 return;
1729 }
1730
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001731 buffer[slength] = 0x00; /* null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001732
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001733 ep = buffer + 1; /* skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001734
1735#ifdef PNG_FLOATING_POINT_SUPPORTED
1736 width = strtod(ep, &vp);
1737 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001738 {
1739 png_warning(png_ptr, "malformed width string in sCAL chunk");
1740 return;
1741 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001742#else
1743#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001744 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1745 if (swidth == NULL)
1746 {
1747 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
1748 return;
1749 }
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001750 png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001751#endif
1752#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001753
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001754 for (ep = buffer; *ep; ep++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001755 /* empty loop */ ;
1756 ep++;
1757
1758#ifdef PNG_FLOATING_POINT_SUPPORTED
1759 height = strtod(ep, &vp);
1760 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001761 {
1762 png_warning(png_ptr, "malformed height string in sCAL chunk");
1763 return;
1764 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001765#else
1766#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001767 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1768 if (swidth == NULL)
1769 {
1770 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
1771 return;
1772 }
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001773 png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001774#endif
1775#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001776
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001777 if (buffer + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001778#ifdef PNG_FLOATING_POINT_SUPPORTED
1779 || width <= 0. || height <= 0.
1780#endif
1781 )
1782 {
1783 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001784 png_free(png_ptr, buffer);
1785#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001786 png_free(png_ptr, swidth);
1787 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001788#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001789 return;
1790 }
1791
1792
1793#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001794 png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
1795#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001796#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001797 png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
1798#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001799#endif
1800
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001801 png_free(png_ptr, buffer);
1802#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1803 png_free(png_ptr, swidth);
1804 png_free(png_ptr, sheight);
1805#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001806}
1807#endif
1808
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001809#if defined(PNG_READ_tIME_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001810void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001811png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001812{
1813 png_byte buf[7];
1814 png_time mod_time;
1815
Andreas Dilger47a0c421997-05-16 02:46:07 -05001816 png_debug(1, "in png_handle_tIME\n");
1817
Guy Schalnate5a37791996-06-05 15:50:50 -05001818 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001819 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001820 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001821 {
1822 png_warning(png_ptr, "Duplicate tIME chunk");
1823 png_crc_finish(png_ptr, length);
1824 return;
1825 }
1826
1827 if (png_ptr->mode & PNG_HAVE_IDAT)
1828 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001829
Guy Schalnat0d580581995-07-20 02:43:20 -05001830 if (length != 7)
1831 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001832 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001833 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001834 return;
1835 }
1836
1837 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001838 if (png_crc_finish(png_ptr, 0))
1839 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001840
1841 mod_time.second = buf[6];
1842 mod_time.minute = buf[5];
1843 mod_time.hour = buf[4];
1844 mod_time.day = buf[3];
1845 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001846 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001847
Andreas Dilger47a0c421997-05-16 02:46:07 -05001848 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001849}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001850#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001851
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001852#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001853/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001854void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001855png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001856{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001857 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001858 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001859 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001860 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001861 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001862 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001863
1864 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001865
Guy Schalnate5a37791996-06-05 15:50:50 -05001866 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1867 png_error(png_ptr, "Missing IHDR before tEXt");
1868
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001869 if (png_ptr->mode & PNG_HAVE_IDAT)
1870 png_ptr->mode |= PNG_AFTER_IDAT;
1871
Andreas Dilger47a0c421997-05-16 02:46:07 -05001872#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001873 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001874 {
1875 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001876 skip = length - (png_uint_32)65535L;
1877 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001878 }
1879#endif
1880
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001881 key = (png_charp)png_malloc_warn(png_ptr, length + 1);
1882 if (key == NULL)
1883 {
1884 png_warning(png_ptr, "No memory to process text chunk.");
1885 return;
1886 }
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001887 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001888 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001889
1890 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001891 {
1892 png_free(png_ptr, key);
1893 return;
1894 }
1895
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001896 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001897
1898 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001899 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001900
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001901 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001902 text++;
1903
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001904 text_ptr = (png_textp)png_malloc_warn(png_ptr,
1905 (png_uint_32)png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001906 if (text_ptr == NULL)
1907 {
1908 png_warning(png_ptr, "Not enough memory to process text chunk.");
1909 png_free(png_ptr, key);
1910 return;
1911 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001912 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1913 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001914#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001915 text_ptr->lang = NULL;
1916 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001917 text_ptr->itxt_length = 0;
1918#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001919 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001920 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001921
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001922 ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001923
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -05001924 png_free(png_ptr, key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001925 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001926 if (ret)
1927 png_warning(png_ptr, "Insufficient memory to process text chunk.");
Guy Schalnat0d580581995-07-20 02:43:20 -05001928}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001929#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001930
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001931#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001932/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001933void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001934png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001935{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001936 png_textp text_ptr;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001937 png_charp chunkdata;
Guy Schalnat6d764711995-12-19 03:22:19 -06001938 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001939 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001940 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001941 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001942
1943 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001944 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1945 png_error(png_ptr, "Missing IHDR before zTXt");
1946
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001947 if (png_ptr->mode & PNG_HAVE_IDAT)
1948 png_ptr->mode |= PNG_AFTER_IDAT;
1949
Andreas Dilger47a0c421997-05-16 02:46:07 -05001950#ifdef PNG_MAX_MALLOC_64K
1951 /* We will no doubt have problems with chunks even half this size, but
1952 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001953 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001954 {
1955 png_warning(png_ptr,"zTXt chunk too large to fit in memory");
1956 png_crc_finish(png_ptr, length);
1957 return;
1958 }
1959#endif
1960
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001961 chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1962 if (chunkdata == NULL)
1963 {
1964 png_warning(png_ptr,"Out of memory processing zTXt chunk.");
1965 return;
1966 }
1967 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001968 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001969 if (png_crc_finish(png_ptr, 0))
1970 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001971 png_free(png_ptr, chunkdata);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001972 return;
1973 }
1974
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001975 chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001976
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001977 for (text = chunkdata; *text; text++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001978 /* empty loop */ ;
1979
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001980 /* zTXt must have some text after the chunkdataword */
1981 if (text == chunkdata + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001982 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001983 comp_type = PNG_TEXT_COMPRESSION_NONE;
Guy Schalnat69b14481996-01-10 02:56:49 -06001984 png_warning(png_ptr, "Zero length zTXt chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001985 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001986 else
Guy Schalnat0d580581995-07-20 02:43:20 -05001987 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001988 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06001989 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
1990 {
1991 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
1992 comp_type = PNG_TEXT_COMPRESSION_zTXt;
1993 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001994 text++; /* skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05001995 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001996 prefix_len = text - chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05001997
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001998 chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001999 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002000
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05002001 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2002 (png_uint_32)png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002003 if (text_ptr == NULL)
2004 {
2005 png_warning(png_ptr,"Not enough memory to process zTXt chunk.");
2006 png_free(png_ptr, chunkdata);
2007 return;
2008 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002009 text_ptr->compression = comp_type;
2010 text_ptr->key = chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002011#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002012 text_ptr->lang = NULL;
2013 text_ptr->lang_key = NULL;
2014 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002015#endif
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002016 text_ptr->text = chunkdata + prefix_len;
2017 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002018
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002019 ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002020
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002021 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002022 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002023 if (ret)
2024 png_error(png_ptr, "Insufficient memory to store zTXt chunk.");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002025}
2026#endif
2027
2028#if defined(PNG_READ_iTXt_SUPPORTED)
2029/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002030void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002031png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2032{
2033 png_textp text_ptr;
2034 png_charp chunkdata;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002035 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002036 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002037 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002038 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002039 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002040
2041 png_debug(1, "in png_handle_iTXt\n");
2042
2043 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2044 png_error(png_ptr, "Missing IHDR before iTXt");
2045
2046 if (png_ptr->mode & PNG_HAVE_IDAT)
2047 png_ptr->mode |= PNG_AFTER_IDAT;
2048
2049#ifdef PNG_MAX_MALLOC_64K
2050 /* We will no doubt have problems with chunks even half this size, but
2051 there is no hard and fast rule to tell us where to stop. */
2052 if (length > (png_uint_32)65535L)
2053 {
2054 png_warning(png_ptr,"iTXt chunk too large to fit in memory");
2055 png_crc_finish(png_ptr, length);
2056 return;
2057 }
2058#endif
2059
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002060 chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2061 if (chunkdata == NULL)
2062 {
2063 png_warning(png_ptr, "No memory to process iTXt chunk.");
2064 return;
2065 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002066 slength = (png_size_t)length;
2067 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002068 if (png_crc_finish(png_ptr, 0))
2069 {
2070 png_free(png_ptr, chunkdata);
2071 return;
2072 }
2073
2074 chunkdata[slength] = 0x00;
2075
2076 for (lang = chunkdata; *lang; lang++)
2077 /* empty loop */ ;
2078 lang++; /* skip NUL separator */
2079
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002080 /* iTXt must have a language tag (possibly empty), two compression bytes,
2081 translated keyword (possibly empty), and possibly some text after the
2082 keyword */
2083
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002084 if (lang >= chunkdata + slength)
2085 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002086 comp_flag = PNG_TEXT_COMPRESSION_NONE;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002087 png_warning(png_ptr, "Zero length iTXt chunk");
2088 }
2089 else
2090 {
2091 comp_flag = *lang++;
2092 comp_type = *lang++;
2093 }
2094
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002095 for (lang_key = lang; *lang_key; lang_key++)
2096 /* empty loop */ ;
2097 lang_key++; /* skip NUL separator */
2098
2099 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002100 /* empty loop */ ;
2101 text++; /* skip NUL separator */
2102
2103 prefix_len = text - chunkdata;
2104
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002105 key=chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002106 if (comp_flag)
2107 chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002108 (size_t)length, prefix_len, &data_len);
2109 else
2110 data_len=png_strlen(chunkdata + prefix_len);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05002111 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2112 (png_uint_32)png_sizeof(png_text));
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002113 if (text_ptr == NULL)
2114 {
2115 png_warning(png_ptr,"Not enough memory to process iTXt chunk.");
2116 png_free(png_ptr, chunkdata);
2117 return;
2118 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002119 text_ptr->compression = (int)comp_flag + 1;
2120 text_ptr->lang_key = chunkdata+(lang_key-key);
2121 text_ptr->lang = chunkdata+(lang-key);
2122 text_ptr->itxt_length = data_len;
2123 text_ptr->text_length = 0;
2124 text_ptr->key = chunkdata;
2125 text_ptr->text = chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002126
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002127 ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002128
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002129 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002130 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002131 if (ret)
2132 png_error(png_ptr, "Insufficient memory to store iTXt chunk.");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002133}
2134#endif
2135
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002136/* This function is called when we haven't found a handler for a
2137 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002138 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2139 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2140 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002141void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002142png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2143{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002144 png_uint_32 skip = 0;
2145
Andreas Dilger47a0c421997-05-16 02:46:07 -05002146 png_debug(1, "in png_handle_unknown\n");
2147
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002148 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002149 {
2150#ifdef PNG_USE_LOCAL_ARRAYS
2151 PNG_IDAT;
2152#endif
2153 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
2154 png_ptr->mode |= PNG_AFTER_IDAT;
2155 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002156
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002157 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
2158
2159 if (!(png_ptr->chunk_name[0] & 0x20))
2160 {
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002161#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002162 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2163 HANDLE_CHUNK_ALWAYS
2164#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002165 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002166#endif
2167 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002168#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002169 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002170 }
2171
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002172#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
2173 if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
2174 {
2175 png_unknown_chunk chunk;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002176
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002177#ifdef PNG_MAX_MALLOC_64K
2178 if (length > (png_uint_32)65535L)
2179 {
2180 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2181 skip = length - (png_uint_32)65535L;
2182 length = (png_uint_32)65535L;
2183 }
2184#endif
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002185 png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002186 chunk.data = (png_bytep)png_malloc(png_ptr, length);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002187 chunk.size = (png_size_t)length;
2188 png_crc_read(png_ptr, (png_bytep)chunk.data, length);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002189#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002190 if(png_ptr->read_user_chunk_fn != NULL)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002191 {
2192 /* callback to user unknown chunk handler */
2193 if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0)
2194 {
2195 if (!(png_ptr->chunk_name[0] & 0x20))
2196 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2197 HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002198 {
2199 png_free(png_ptr, chunk.data);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002200 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002201 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002202 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
2203 }
2204 }
2205 else
2206#endif
2207 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002208 png_free(png_ptr, chunk.data);
2209 }
2210 else
2211#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002212 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002213
2214 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002215
2216#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002217 if (&info_ptr == NULL) /* quiet compiler warnings about unused info_ptr */
2218 return;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002219#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002220}
2221
2222/* This function is called to verify that a chunk name is valid.
2223 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002224 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002225 functions to handle unknown critical chunks after we check that
2226 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002227
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002228#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002229
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002230void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002231png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2232{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002233 png_debug(1, "in png_check_chunk_name\n");
2234 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
2235 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002236 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002237 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002238 }
2239}
2240
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002241/* Combines the row recently read in with the existing pixels in the
2242 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002243 This routine also handles the two methods of progressive display
2244 of interlaced images, depending on the mask value.
2245 The mask value describes which pixels are to be combined with
2246 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002247 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002248 a zero indicates the pixel is to be skipped. This is in addition
2249 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002250 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002251#ifndef PNG_HAVE_ASSEMBLER_COMBINE_ROW
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002252void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002253png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002254{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002255 png_debug(1,"in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002256 if (mask == 0xff)
2257 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002258 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002259 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002260 }
2261 else
2262 {
2263 switch (png_ptr->row_info.pixel_depth)
2264 {
2265 case 1:
2266 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002267 png_bytep sp = png_ptr->row_buf + 1;
2268 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002269 int s_inc, s_start, s_end;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002270 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002271 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002272 png_uint_32 i;
2273 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002274
Andreas Dilger47a0c421997-05-16 02:46:07 -05002275#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2276 if (png_ptr->transformations & PNG_PACKSWAP)
2277 {
2278 s_start = 0;
2279 s_end = 7;
2280 s_inc = 1;
2281 }
2282 else
2283#endif
2284 {
2285 s_start = 7;
2286 s_end = 0;
2287 s_inc = -1;
2288 }
2289
2290 shift = s_start;
2291
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002292 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002293 {
2294 if (m & mask)
2295 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002296 int value;
2297
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002298 value = (*sp >> shift) & 0x01;
Guy Schalnat0d580581995-07-20 02:43:20 -05002299 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002300 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002301 }
2302
Andreas Dilger47a0c421997-05-16 02:46:07 -05002303 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002304 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002305 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002306 sp++;
2307 dp++;
2308 }
2309 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002310 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002311
2312 if (m == 1)
2313 m = 0x80;
2314 else
2315 m >>= 1;
2316 }
2317 break;
2318 }
2319 case 2:
2320 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002321 png_bytep sp = png_ptr->row_buf + 1;
2322 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002323 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002324 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002325 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002326 png_uint_32 i;
2327 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002328 int value;
2329
Andreas Dilger47a0c421997-05-16 02:46:07 -05002330#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2331 if (png_ptr->transformations & PNG_PACKSWAP)
2332 {
2333 s_start = 0;
2334 s_end = 6;
2335 s_inc = 2;
2336 }
2337 else
2338#endif
2339 {
2340 s_start = 6;
2341 s_end = 0;
2342 s_inc = -2;
2343 }
2344
2345 shift = s_start;
2346
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002347 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002348 {
2349 if (m & mask)
2350 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002351 value = (*sp >> shift) & 0x03;
Guy Schalnat0d580581995-07-20 02:43:20 -05002352 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002353 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002354 }
2355
Andreas Dilger47a0c421997-05-16 02:46:07 -05002356 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002357 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002358 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002359 sp++;
2360 dp++;
2361 }
2362 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002363 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002364 if (m == 1)
2365 m = 0x80;
2366 else
2367 m >>= 1;
2368 }
2369 break;
2370 }
2371 case 4:
2372 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002373 png_bytep sp = png_ptr->row_buf + 1;
2374 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002375 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002376 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002377 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002378 png_uint_32 i;
2379 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002380 int value;
2381
Andreas Dilger47a0c421997-05-16 02:46:07 -05002382#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2383 if (png_ptr->transformations & PNG_PACKSWAP)
2384 {
2385 s_start = 0;
2386 s_end = 4;
2387 s_inc = 4;
2388 }
2389 else
2390#endif
2391 {
2392 s_start = 4;
2393 s_end = 0;
2394 s_inc = -4;
2395 }
2396 shift = s_start;
2397
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002398 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002399 {
2400 if (m & mask)
2401 {
2402 value = (*sp >> shift) & 0xf;
2403 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002404 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002405 }
2406
Andreas Dilger47a0c421997-05-16 02:46:07 -05002407 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002408 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002409 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002410 sp++;
2411 dp++;
2412 }
2413 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002414 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002415 if (m == 1)
2416 m = 0x80;
2417 else
2418 m >>= 1;
2419 }
2420 break;
2421 }
2422 default:
2423 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002424 png_bytep sp = png_ptr->row_buf + 1;
2425 png_bytep dp = row;
2426 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2427 png_uint_32 i;
2428 png_uint_32 row_width = png_ptr->width;
2429 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002430
Guy Schalnat0d580581995-07-20 02:43:20 -05002431
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002432 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002433 {
2434 if (m & mask)
2435 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002436 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002437 }
2438
2439 sp += pixel_bytes;
2440 dp += pixel_bytes;
2441
2442 if (m == 1)
2443 m = 0x80;
2444 else
2445 m >>= 1;
2446 }
2447 break;
2448 }
2449 }
2450 }
2451}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002452#endif /* !PNG_HAVE_ASSEMBLER_COMBINE_ROW */
Guy Schalnat0d580581995-07-20 02:43:20 -05002453
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002454#ifdef PNG_READ_INTERLACING_SUPPORTED
2455#ifndef PNG_HAVE_ASSEMBLER_READ_INTERLACE /* else in pngvcrd.c, pnggccrd.c */
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002456/* OLD pre-1.0.9 interface:
2457void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2458 png_uint_32 transformations)
2459 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002460void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002461png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002462{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002463 png_row_infop row_info = &(png_ptr->row_info);
2464 png_bytep row = png_ptr->row_buf + 1;
2465 int pass = png_ptr->pass;
2466 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002467#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002468 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002469 /* offset to next interlace block */
2470 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002471#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002472
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002473 png_debug(1,"in png_do_read_interlace (stock C version)\n");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002474 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002475 {
2476 png_uint_32 final_width;
2477
2478 final_width = row_info->width * png_pass_inc[pass];
2479
2480 switch (row_info->pixel_depth)
2481 {
2482 case 1:
2483 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002484 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2485 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002486 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002487 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002488 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002489 png_byte v;
2490 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002491 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002492
Andreas Dilger47a0c421997-05-16 02:46:07 -05002493#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2494 if (transformations & PNG_PACKSWAP)
2495 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002496 sshift = (int)((row_info->width + 7) & 0x07);
2497 dshift = (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002498 s_start = 7;
2499 s_end = 0;
2500 s_inc = -1;
2501 }
2502 else
2503#endif
2504 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002505 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2506 dshift = 7 - (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002507 s_start = 0;
2508 s_end = 7;
2509 s_inc = 1;
2510 }
2511
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002512 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002513 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002514 v = (png_byte)((*sp >> sshift) & 0x01);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002515 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002516 {
2517 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2518 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002519 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002520 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002521 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002522 dp--;
2523 }
2524 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002525 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002526 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002527 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002528 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002529 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002530 sp--;
2531 }
2532 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002533 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002534 }
2535 break;
2536 }
2537 case 2:
2538 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002539 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2540 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002541 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002542 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002543 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002544 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002545
Andreas Dilger47a0c421997-05-16 02:46:07 -05002546#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2547 if (transformations & PNG_PACKSWAP)
2548 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002549 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2550 dshift = (int)(((final_width + 3) & 0x03) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002551 s_start = 6;
2552 s_end = 0;
2553 s_inc = -2;
2554 }
2555 else
2556#endif
2557 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002558 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2559 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002560 s_start = 0;
2561 s_end = 6;
2562 s_inc = 2;
2563 }
2564
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002565 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002566 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002567 png_byte v;
2568 int j;
2569
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002570 v = (png_byte)((*sp >> sshift) & 0x03);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002571 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002572 {
2573 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002574 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002575 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002576 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002577 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002578 dp--;
2579 }
2580 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002581 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002582 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002583 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002584 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002585 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002586 sp--;
2587 }
2588 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002589 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002590 }
2591 break;
2592 }
2593 case 4:
2594 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002595 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2596 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002597 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002598 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002599 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002600 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002601
Andreas Dilger47a0c421997-05-16 02:46:07 -05002602#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2603 if (transformations & PNG_PACKSWAP)
2604 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002605 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2606 dshift = (int)(((final_width + 1) & 0x01) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002607 s_start = 4;
2608 s_end = 0;
2609 s_inc = -4;
2610 }
2611 else
2612#endif
2613 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002614 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2615 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002616 s_start = 0;
2617 s_end = 4;
2618 s_inc = 4;
2619 }
2620
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002621 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002622 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002623 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002624 int j;
2625
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002626 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002627 {
2628 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002629 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002630 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002631 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002632 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002633 dp--;
2634 }
2635 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002636 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002637 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002638 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002639 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002640 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002641 sp--;
2642 }
2643 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002644 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002645 }
2646 break;
2647 }
2648 default:
2649 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002650 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
2651 png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
2652 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002653
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002654 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002655 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002656
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002657 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002658 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002659 png_byte v[8];
2660 int j;
2661
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002662 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002663 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002664 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002665 png_memcpy(dp, v, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002666 dp -= pixel_bytes;
2667 }
2668 sp -= pixel_bytes;
2669 }
2670 break;
2671 }
2672 }
2673 row_info->width = final_width;
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002674 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05002675 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002676#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002677 if (&transformations == NULL) /* silence compiler warning */
2678 return;
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002679#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002680}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002681#endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */
2682#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002683
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002684#ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002685void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002686png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002687 png_bytep prev_row, int filter)
2688{
2689 png_debug(1, "in png_read_filter_row\n");
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05002690 png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002691 switch (filter)
2692 {
2693 case PNG_FILTER_VALUE_NONE:
2694 break;
2695 case PNG_FILTER_VALUE_SUB:
2696 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002697 png_uint_32 i;
2698 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002699 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002700 png_bytep rp = row + bpp;
2701 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002702
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002703 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002704 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002705 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2706 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002707 }
2708 break;
2709 }
2710 case PNG_FILTER_VALUE_UP:
2711 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002712 png_uint_32 i;
2713 png_uint_32 istop = row_info->rowbytes;
2714 png_bytep rp = row;
2715 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002716
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002717 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002718 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002719 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2720 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002721 }
2722 break;
2723 }
2724 case PNG_FILTER_VALUE_AVG:
2725 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002726 png_uint_32 i;
2727 png_bytep rp = row;
2728 png_bytep pp = prev_row;
2729 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002730 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002731 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002732
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002733 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002734 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002735 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002736 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002737 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002738 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002739
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002740 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002741 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002742 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002743 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002744 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002745 }
2746 break;
2747 }
2748 case PNG_FILTER_VALUE_PAETH:
2749 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002750 png_uint_32 i;
2751 png_bytep rp = row;
2752 png_bytep pp = prev_row;
2753 png_bytep lp = row;
2754 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002755 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002756 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002757
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002758 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002759 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002760 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2761 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002762 }
2763
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002764 for (i = 0; i < istop; i++) /* use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002765 {
2766 int a, b, c, pa, pb, pc, p;
2767
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002768 a = *lp++;
2769 b = *pp++;
2770 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002771
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002772 p = b - c;
2773 pc = a - c;
2774
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002775#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002776 pa = abs(p);
2777 pb = abs(pc);
2778 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002779#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002780 pa = p < 0 ? -p : p;
2781 pb = pc < 0 ? -pc : pc;
2782 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002783#endif
2784
2785 /*
2786 if (pa <= pb && pa <= pc)
2787 p = a;
2788 else if (pb <= pc)
2789 p = b;
2790 else
2791 p = c;
2792 */
2793
2794 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2795
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002796 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2797 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002798 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002799 break;
2800 }
2801 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002802 png_warning(png_ptr, "Ignoring bad adaptive filter type");
2803 *row=0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002804 break;
2805 }
2806}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002807#endif /* !PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
Guy Schalnat0d580581995-07-20 02:43:20 -05002808
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002809void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002810png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002811{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002812#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002813 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002814
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002815 /* start of interlace block */
2816 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002817
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002818 /* offset to next interlace block */
2819 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002820
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002821 /* start of interlace block in the y direction */
2822 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002823
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002824 /* offset to next interlace block in the y direction */
2825 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002826#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002827
Andreas Dilger47a0c421997-05-16 02:46:07 -05002828 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002829 png_ptr->row_number++;
2830 if (png_ptr->row_number < png_ptr->num_rows)
2831 return;
2832
2833 if (png_ptr->interlaced)
2834 {
2835 png_ptr->row_number = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002836 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002837 do
2838 {
2839 png_ptr->pass++;
2840 if (png_ptr->pass >= 7)
2841 break;
2842 png_ptr->iwidth = (png_ptr->width +
2843 png_pass_inc[png_ptr->pass] - 1 -
2844 png_pass_start[png_ptr->pass]) /
2845 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002846
2847 png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
2848 png_ptr->iwidth) + 1;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002849
Guy Schalnat0d580581995-07-20 02:43:20 -05002850 if (!(png_ptr->transformations & PNG_INTERLACE))
2851 {
2852 png_ptr->num_rows = (png_ptr->height +
2853 png_pass_yinc[png_ptr->pass] - 1 -
2854 png_pass_ystart[png_ptr->pass]) /
2855 png_pass_yinc[png_ptr->pass];
2856 if (!(png_ptr->num_rows))
2857 continue;
2858 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002859 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002860 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002861 } while (png_ptr->iwidth == 0);
2862
2863 if (png_ptr->pass < 7)
2864 return;
2865 }
2866
Guy Schalnate5a37791996-06-05 15:50:50 -05002867 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002868 {
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002869#ifdef PNG_USE_LOCAL_ARRAYS
2870 PNG_IDAT;
2871#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002872 char extra;
2873 int ret;
2874
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002875 png_ptr->zstream.next_out = (Byte *)&extra;
2876 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002877 for(;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05002878 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002879 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002880 {
2881 while (!png_ptr->idat_size)
2882 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002883 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002884
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002885 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002886
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002887 png_read_data(png_ptr, chunk_length, 4);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05002888 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
Guy Schalnat0d580581995-07-20 02:43:20 -05002889 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002890 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002891 if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002892 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002893
2894 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002895 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2896 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002897 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002898 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2899 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2900 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002901 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002902 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002903 if (ret == Z_STREAM_END)
2904 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002905 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002906 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05002907 png_warning(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002908 png_ptr->mode |= PNG_AFTER_IDAT;
2909 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002910 break;
2911 }
2912 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002913 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05002914 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05002915
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002916 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05002917 {
2918 png_warning(png_ptr, "Extra compressed data.");
2919 png_ptr->mode |= PNG_AFTER_IDAT;
2920 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
2921 break;
2922 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002923
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002924 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002925 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002926 }
2927
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002928 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05002929 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002930
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002931 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05002932
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002933 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002934}
2935
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002936void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002937png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002938{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002939#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002940 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002941
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002942 /* start of interlace block */
2943 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002944
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002945 /* offset to next interlace block */
2946 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002947
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002948 /* start of interlace block in the y direction */
2949 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002950
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002951 /* offset to next interlace block in the y direction */
2952 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002953#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002954
Guy Schalnat0d580581995-07-20 02:43:20 -05002955 int max_pixel_depth;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002956 png_uint_32 row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002957
Andreas Dilger47a0c421997-05-16 02:46:07 -05002958 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002959 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002960 png_init_read_transformations(png_ptr);
2961 if (png_ptr->interlaced)
2962 {
2963 if (!(png_ptr->transformations & PNG_INTERLACE))
2964 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
2965 png_pass_ystart[0]) / png_pass_yinc[0];
2966 else
2967 png_ptr->num_rows = png_ptr->height;
2968
2969 png_ptr->iwidth = (png_ptr->width +
2970 png_pass_inc[png_ptr->pass] - 1 -
2971 png_pass_start[png_ptr->pass]) /
2972 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002973
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05002974 row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
2975
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002976 png_ptr->irowbytes = (png_size_t)row_bytes;
2977 if((png_uint_32)png_ptr->irowbytes != row_bytes)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002978 png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002979 }
2980 else
2981 {
2982 png_ptr->num_rows = png_ptr->height;
2983 png_ptr->iwidth = png_ptr->width;
2984 png_ptr->irowbytes = png_ptr->rowbytes + 1;
2985 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002986 max_pixel_depth = png_ptr->pixel_depth;
2987
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002988#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002989 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002990 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002991#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002992
Guy Schalnate5a37791996-06-05 15:50:50 -05002993#if defined(PNG_READ_EXPAND_SUPPORTED)
2994 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002995 {
2996 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2997 {
2998 if (png_ptr->num_trans)
2999 max_pixel_depth = 32;
3000 else
3001 max_pixel_depth = 24;
3002 }
3003 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3004 {
3005 if (max_pixel_depth < 8)
3006 max_pixel_depth = 8;
3007 if (png_ptr->num_trans)
3008 max_pixel_depth *= 2;
3009 }
3010 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3011 {
3012 if (png_ptr->num_trans)
3013 {
3014 max_pixel_depth *= 4;
3015 max_pixel_depth /= 3;
3016 }
3017 }
3018 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003019#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003020
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003021#if defined(PNG_READ_FILLER_SUPPORTED)
3022 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003023 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003024 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3025 max_pixel_depth = 32;
3026 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003027 {
3028 if (max_pixel_depth <= 8)
3029 max_pixel_depth = 16;
3030 else
3031 max_pixel_depth = 32;
3032 }
3033 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3034 {
3035 if (max_pixel_depth <= 32)
3036 max_pixel_depth = 32;
3037 else
3038 max_pixel_depth = 64;
3039 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003040 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003041#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003042
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003043#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05003044 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3045 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003046 if (
3047#if defined(PNG_READ_EXPAND_SUPPORTED)
3048 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
3049#endif
3050#if defined(PNG_READ_FILLER_SUPPORTED)
3051 (png_ptr->transformations & (PNG_FILLER)) ||
3052#endif
3053 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003054 {
3055 if (max_pixel_depth <= 16)
3056 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003057 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003058 max_pixel_depth = 64;
3059 }
3060 else
3061 {
3062 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003063 {
3064 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3065 max_pixel_depth = 32;
3066 else
3067 max_pixel_depth = 24;
3068 }
3069 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3070 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003071 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003072 max_pixel_depth = 48;
3073 }
3074 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003075#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003076
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003077#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3078defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003079 if(png_ptr->transformations & PNG_USER_TRANSFORM)
3080 {
3081 int user_pixel_depth=png_ptr->user_transform_depth*
3082 png_ptr->user_transform_channels;
3083 if(user_pixel_depth > max_pixel_depth)
3084 max_pixel_depth=user_pixel_depth;
3085 }
3086#endif
3087
Guy Schalnat0d580581995-07-20 02:43:20 -05003088 /* align the width on the next larger 8 pixels. Mainly used
3089 for interlacing */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003090 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Guy Schalnat0d580581995-07-20 02:43:20 -05003091 /* calculate the maximum bytes needed, adding a byte and a pixel
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003092 for safety's sake */
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003093 row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) +
Guy Schalnat0d580581995-07-20 02:43:20 -05003094 1 + ((max_pixel_depth + 7) >> 3);
3095#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003096 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003097 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003098#endif
Glenn Randers-Pehrson1b8e5672001-08-25 06:46:06 -05003099 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
3100 png_ptr->row_buf = png_ptr->big_row_buf+32;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -05003101#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05003102 png_ptr->row_buf_size = row_bytes;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -05003103#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003104
3105#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003106 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003107 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003108#endif
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05003109 if ((png_uint_32)png_ptr->rowbytes + 1 > PNG_SIZE_MAX)
3110 png_error(png_ptr, "Row has too many bytes to allocate in memory.");
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06003111 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
3112 png_ptr->rowbytes + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05003113
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06003114 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003115
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05003116 png_debug1(3, "width = %lu,\n", png_ptr->width);
3117 png_debug1(3, "height = %lu,\n", png_ptr->height);
3118 png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
3119 png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
3120 png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
3121 png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05003122
Guy Schalnate5a37791996-06-05 15:50:50 -05003123 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003124}