blob: 14b8f82da7404b33733b3fe766fa3d9296f522fc [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Andreas Dilger47a0c421997-05-16 02:46:07 -05002/* pngrutil.c - utilities to read a PNG file
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06003 *
Glenn Randers-Pehrson299d7352002-05-01 16:55:46 -05004 * libpng 1.2.3rc3 - May 1, 2002
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrsonc6de22d2002-02-23 18:55:25 -06006 * Copyright (c) 1998-2002 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05007 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06009 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050010 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060011 * libpng itself during the course of reading an image.
12 */
Guy Schalnat0d580581995-07-20 02:43:20 -050013
14#define PNG_INTERNAL
15#include "png.h"
16
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -050017#if defined(_WIN32_WCE)
18/* strtod() function is not supported on WindowsCE */
19# ifdef PNG_FLOATING_POINT_SUPPORTED
20__inline double strtod(const char *nptr, char **endptr)
21{
22 double result = 0;
23 int len;
24 wchar_t *str, *end;
25
26 len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
27 str = (wchar_t *)malloc(len * sizeof(wchar_t));
28 if ( NULL != str )
29 {
30 MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
31 result = wcstod(str, &end);
32 len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -050033 *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -050034 free(str);
35 }
36 return result;
37}
38# endif
39#endif
40
Andreas Dilger47a0c421997-05-16 02:46:07 -050041#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050042/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050043png_uint_32 /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -060044png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050045{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050046 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
Guy Schalnat0d580581995-07-20 02:43:20 -050047 ((png_uint_32)(*(buf + 1)) << 16) +
48 ((png_uint_32)(*(buf + 2)) << 8) +
49 (png_uint_32)(*(buf + 3));
50
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060051 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050052}
53
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -060054#if defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050055/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Andreas Dilger47a0c421997-05-16 02:46:07 -050056 * data is stored in the PNG file in two's complement format, and it is
57 * assumed that the machine format for signed integers is the same. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050058png_int_32 /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -050059png_get_int_32(png_bytep buf)
60{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050061 png_int_32 i = ((png_int_32)(*buf) << 24) +
Andreas Dilger47a0c421997-05-16 02:46:07 -050062 ((png_int_32)(*(buf + 1)) << 16) +
63 ((png_int_32)(*(buf + 2)) << 8) +
64 (png_int_32)(*(buf + 3));
65
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060066 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050067}
68#endif /* PNG_READ_pCAL_SUPPORTED */
69
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050070/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050071png_uint_16 /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -060072png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050073{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050074 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060075 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050076
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060077 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050078}
Andreas Dilger47a0c421997-05-16 02:46:07 -050079#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050080
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060081/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050082void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -050083png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050084{
Guy Schalnat6d764711995-12-19 03:22:19 -060085 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -050086 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050087}
88
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060089/* Optionally skip data and then check the CRC. Depending on whether we
90 are reading a ancillary or critical chunk, and how the program has set
Andreas Dilger47a0c421997-05-16 02:46:07 -050091 things up, we may calculate the CRC on the data and print a message.
92 Returns '1' if there was a CRC error, '0' otherwise. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050093int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060094png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -050095{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -050096 png_size_t i;
97 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -050098
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -050099 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600100 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500101 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500102 }
103 if (i)
104 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500105 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500106 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600107
Andreas Dilger47a0c421997-05-16 02:46:07 -0500108 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600109 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600110 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600111 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
112 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600113 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600114 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600115 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600116 }
117 else
118 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600119 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600120 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600121 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600122 }
123
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600124 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500125}
126
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600127/* Compare the CRC stored in the PNG file with that calculated by libpng from
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600128 the data it has read thus far. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500129int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600130png_crc_error(png_structp png_ptr)
131{
132 png_byte crc_bytes[4];
133 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500134 int need_crc = 1;
135
136 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
137 {
138 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
139 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
140 need_crc = 0;
141 }
142 else /* critical */
143 {
144 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
145 need_crc = 0;
146 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600147
148 png_read_data(png_ptr, crc_bytes, 4);
149
Andreas Dilger47a0c421997-05-16 02:46:07 -0500150 if (need_crc)
151 {
152 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600153 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500154 }
155 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600156 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600157}
158
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600159#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -0500160 defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600161/*
162 * Decompress trailing data in a chunk. The assumption is that chunkdata
163 * points at an allocated area holding the contents of a chunk with a
164 * trailing compressed part. What we get back is an allocated area
165 * holding the original prefix part and an uncompressed version of the
166 * trailing part (the malloc area passed in is freed).
167 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500168png_charp /* PRIVATE */
169png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600170 png_charp chunkdata, png_size_t chunklength,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600171 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600172{
173 static char msg[] = "Error decoding compressed text";
174 png_charp text = NULL;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600175 png_size_t text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600176
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600177 if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600178 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500179 int ret = Z_OK;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600180 png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
181 png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
182 png_ptr->zstream.next_out = png_ptr->zbuf;
183 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
184
185 text_size = 0;
186 text = NULL;
187
188 while (png_ptr->zstream.avail_in)
189 {
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500190 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600191 if (ret != Z_OK && ret != Z_STREAM_END)
192 {
193 if (png_ptr->zstream.msg != NULL)
194 png_warning(png_ptr, png_ptr->zstream.msg);
195 else
196 png_warning(png_ptr, msg);
197 inflateReset(&png_ptr->zstream);
198 png_ptr->zstream.avail_in = 0;
199
200 if (text == NULL)
201 {
202 text_size = prefix_size + sizeof(msg) + 1;
203 text = (png_charp)png_malloc(png_ptr, text_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500204 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600205 }
206
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500207 text[text_size - 1] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600208
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500209 /* Copy what we can of the error message into the text chunk */
210 text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
211 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
212 png_memcpy(text + prefix_size, msg, text_size + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600213 break;
214 }
215 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
216 {
217 if (text == NULL)
218 {
219 text_size = prefix_size +
220 png_ptr->zbuf_size - png_ptr->zstream.avail_out;
221 text = (png_charp)png_malloc(png_ptr, text_size + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500222 png_memcpy(text + prefix_size, png_ptr->zbuf,
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500223 text_size - prefix_size);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500224 png_memcpy(text, chunkdata, prefix_size);
225 *(text + text_size) = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600226 }
227 else
228 {
229 png_charp tmp;
230
231 tmp = text;
232 text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size +
233 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
234 png_memcpy(text, tmp, text_size);
235 png_free(png_ptr, tmp);
236 png_memcpy(text + text_size, png_ptr->zbuf,
237 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
238 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
239 *(text + text_size) = 0x00;
240 }
241 if (ret == Z_STREAM_END)
242 break;
243 else
244 {
245 png_ptr->zstream.next_out = png_ptr->zbuf;
246 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
247 }
248 }
249 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500250 if (ret != Z_STREAM_END)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500251 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500252#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500253 char umsg[50];
254
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500255 if (ret == Z_BUF_ERROR)
256 sprintf(umsg,"Buffer error in compressed datastream in %s chunk",
257 png_ptr->chunk_name);
258 else if (ret == Z_DATA_ERROR)
259 sprintf(umsg,"Data error in compressed datastream in %s chunk",
260 png_ptr->chunk_name);
261 else
262 sprintf(umsg,"Incomplete compressed datastream in %s chunk",
263 png_ptr->chunk_name);
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500264 png_warning(png_ptr, umsg);
265#else
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500266 png_warning(png_ptr,
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500267 "Incomplete compressed datastream in chunk other than IDAT");
268#endif
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600269 text_size=prefix_size;
270 if (text == NULL)
271 {
272 text = (png_charp)png_malloc(png_ptr, text_size+1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500273 png_memcpy(text, chunkdata, prefix_size);
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600274 }
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500275 *(text + text_size) = 0x00;
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500276 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600277
278 inflateReset(&png_ptr->zstream);
279 png_ptr->zstream.avail_in = 0;
280
281 png_free(png_ptr, chunkdata);
282 chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600283 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600284 }
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600285 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600286 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500287#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600288 char umsg[50];
289
290 sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
291 png_warning(png_ptr, umsg);
292#else
293 png_warning(png_ptr, "Unknown zTXt compression type");
294#endif
295
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -0600296 *(chunkdata + prefix_size) = 0x00;
297 *newlength=prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600298 }
299
300 return chunkdata;
301}
302#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600303
Guy Schalnat0d580581995-07-20 02:43:20 -0500304/* read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500305void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600306png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500307{
308 png_byte buf[13];
309 png_uint_32 width, height;
310 int bit_depth, color_type, compression_type, filter_type;
311 int interlace_type;
312
Andreas Dilger47a0c421997-05-16 02:46:07 -0500313 png_debug(1, "in png_handle_IHDR\n");
314
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600315 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500316 png_error(png_ptr, "Out of place IHDR");
317
Guy Schalnat0d580581995-07-20 02:43:20 -0500318 /* check the length */
319 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600320 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500321
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600322 png_ptr->mode |= PNG_HAVE_IHDR;
323
Guy Schalnat0d580581995-07-20 02:43:20 -0500324 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600325 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500326
327 width = png_get_uint_32(buf);
328 height = png_get_uint_32(buf + 4);
329 bit_depth = buf[8];
330 color_type = buf[9];
331 compression_type = buf[10];
332 filter_type = buf[11];
333 interlace_type = buf[12];
334
Guy Schalnat0d580581995-07-20 02:43:20 -0500335
336 /* set internal variables */
337 png_ptr->width = width;
338 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600339 png_ptr->bit_depth = (png_byte)bit_depth;
340 png_ptr->interlaced = (png_byte)interlace_type;
341 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500342#if defined(PNG_MNG_FEATURES_SUPPORTED)
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600343 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500344#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500345
346 /* find number of channels */
347 switch (png_ptr->color_type)
348 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500349 case PNG_COLOR_TYPE_GRAY:
350 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500351 png_ptr->channels = 1;
352 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500353 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500354 png_ptr->channels = 3;
355 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500356 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500357 png_ptr->channels = 2;
358 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500359 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500360 png_ptr->channels = 4;
361 break;
362 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600363
Guy Schalnat0d580581995-07-20 02:43:20 -0500364 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600365 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600366 png_ptr->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500367 png_ptr->rowbytes = ((png_ptr->width *
368 (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500369 png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
370 png_debug1(3,"channels = %d\n", png_ptr->channels);
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -0500371 png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500372 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
373 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500374}
375
376/* read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500377void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600378png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500379{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600380 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600381 int num, i;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500382#ifndef PNG_NO_POINTER_INDEXING
383 png_colorp pal_ptr;
384#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500385
Andreas Dilger47a0c421997-05-16 02:46:07 -0500386 png_debug(1, "in png_handle_PLTE\n");
387
Guy Schalnate5a37791996-06-05 15:50:50 -0500388 if (!(png_ptr->mode & PNG_HAVE_IHDR))
389 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600390 else if (png_ptr->mode & PNG_HAVE_IDAT)
391 {
392 png_warning(png_ptr, "Invalid PLTE after IDAT");
393 png_crc_finish(png_ptr, length);
394 return;
395 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500396 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600397 png_error(png_ptr, "Duplicate PLTE chunk");
398
399 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500400
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500401 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
402 {
403 png_warning(png_ptr,
404 "Ignoring PLTE chunk in grayscale PNG");
405 png_crc_finish(png_ptr, length);
406 return;
407 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500408#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
409 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
410 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600411 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500412 return;
413 }
414#endif
415
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600416 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500417 {
418 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
419 {
420 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600421 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500422 return;
423 }
424 else
425 {
426 png_error(png_ptr, "Invalid palette chunk");
427 }
428 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500429
430 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500431
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500432#ifndef PNG_NO_POINTER_INDEXING
433 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
434 {
435 png_byte buf[3];
436
437 png_crc_read(png_ptr, buf, 3);
438 pal_ptr->red = buf[0];
439 pal_ptr->green = buf[1];
440 pal_ptr->blue = buf[2];
441 }
442#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600443 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500444 {
445 png_byte buf[3];
446
447 png_crc_read(png_ptr, buf, 3);
448 /* don't depend upon png_color being any order */
449 palette[i].red = buf[0];
450 palette[i].green = buf[1];
451 palette[i].blue = buf[2];
452 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500453#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600454
455 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
456 whatever the normal CRC configuration tells us. However, if we
457 have an RGB image, the PLTE can be considered ancillary, so
458 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600459#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600460 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600461#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600462 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500463 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600464 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600465#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600466 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
467 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600468 /* If we don't want to use the data from an ancillary chunk,
469 we have two options: an error abort, or a warning and we
470 ignore the data in this chunk (which should be OK, since
471 it's considered ancillary for a RGB or RGBA image). */
472 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
473 {
474 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
475 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600476 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600477 }
478 else
479 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600480 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600481 return;
482 }
483 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500484 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600485 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
486 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600487 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600488 }
489 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600490#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500491
Andreas Dilger47a0c421997-05-16 02:46:07 -0500492 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500493
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500494#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500495 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
496 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600497 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500498 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500499 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500500 {
501 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500502 png_ptr->num_trans = (png_uint_16)num;
503 }
504 if (info_ptr->num_trans > (png_uint_16)num)
505 {
506 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
507 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500508 }
509 }
510 }
511#endif
512
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600513}
Guy Schalnate5a37791996-06-05 15:50:50 -0500514
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500515void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600516png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
517{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500518 png_debug(1, "in png_handle_IEND\n");
519
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600520 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
521 {
522 png_error(png_ptr, "No image in file");
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -0600523
Glenn Randers-Pehrsone68f5a32001-05-14 09:20:53 -0500524 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600525 }
526
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600527 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600528
529 if (length != 0)
530 {
531 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600532 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500533 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500534}
535
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500536#if defined(PNG_READ_gAMA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500537void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600538png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500539{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600540 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600541#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500542 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600543#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500544 png_byte buf[4];
545
Andreas Dilger47a0c421997-05-16 02:46:07 -0500546 png_debug(1, "in png_handle_gAMA\n");
547
Guy Schalnate5a37791996-06-05 15:50:50 -0500548 if (!(png_ptr->mode & PNG_HAVE_IHDR))
549 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600550 else if (png_ptr->mode & PNG_HAVE_IDAT)
551 {
552 png_warning(png_ptr, "Invalid gAMA after IDAT");
553 png_crc_finish(png_ptr, length);
554 return;
555 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500556 else if (png_ptr->mode & PNG_HAVE_PLTE)
557 /* Should be an error, but we can cope with it */
558 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600559
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600560 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600561#if defined(PNG_READ_sRGB_SUPPORTED)
562 && !(info_ptr->valid & PNG_INFO_sRGB)
563#endif
564 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600565 {
566 png_warning(png_ptr, "Duplicate gAMA chunk");
567 png_crc_finish(png_ptr, length);
568 return;
569 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500570
Guy Schalnat0d580581995-07-20 02:43:20 -0500571 if (length != 4)
572 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600573 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600574 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500575 return;
576 }
577
578 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600579 if (png_crc_finish(png_ptr, 0))
580 return;
581
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600582 igamma = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500583 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500584 if (igamma == 0)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500585 {
586 png_warning(png_ptr,
587 "Ignoring gAMA chunk with gamma=0");
588 return;
589 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500590
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600591#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600592 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600593 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600594 {
595 png_warning(png_ptr,
596 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500597#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600598 fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600599#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600600 return;
601 }
602#endif /* PNG_READ_sRGB_SUPPORTED */
603
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600604#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600605 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600606# ifdef PNG_READ_GAMMA_SUPPORTED
607 png_ptr->gamma = file_gamma;
608# endif
609 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600610#endif
611#ifdef PNG_FIXED_POINT_SUPPORTED
612 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
613#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500614}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500615#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500616
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500617#if defined(PNG_READ_sBIT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500618void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600619png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500620{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500621 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600622 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600623
Andreas Dilger47a0c421997-05-16 02:46:07 -0500624 png_debug(1, "in png_handle_sBIT\n");
625
Guy Schalnat69b14481996-01-10 02:56:49 -0600626 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500627
Guy Schalnate5a37791996-06-05 15:50:50 -0500628 if (!(png_ptr->mode & PNG_HAVE_IHDR))
629 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600630 else if (png_ptr->mode & PNG_HAVE_IDAT)
631 {
632 png_warning(png_ptr, "Invalid sBIT after IDAT");
633 png_crc_finish(png_ptr, length);
634 return;
635 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500636 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600637 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500638 /* Should be an error, but we can cope with it */
639 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600640 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600641 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600642 {
643 png_warning(png_ptr, "Duplicate sBIT chunk");
644 png_crc_finish(png_ptr, length);
645 return;
646 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500647
Guy Schalnat0d580581995-07-20 02:43:20 -0500648 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600649 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500650 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500651 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500652
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600653 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500654 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600655 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600656 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600657 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500658 }
659
Andreas Dilger47a0c421997-05-16 02:46:07 -0500660 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600661 if (png_crc_finish(png_ptr, 0))
662 return;
663
Guy Schalnat0d580581995-07-20 02:43:20 -0500664 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
665 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600666 png_ptr->sig_bit.red = buf[0];
667 png_ptr->sig_bit.green = buf[1];
668 png_ptr->sig_bit.blue = buf[2];
669 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500670 }
671 else
672 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600673 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600674 png_ptr->sig_bit.red = buf[0];
675 png_ptr->sig_bit.green = buf[0];
676 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600677 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500678 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500679 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500680}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500681#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500682
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500683#if defined(PNG_READ_cHRM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500684void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600685png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500686{
687 png_byte buf[4];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600688#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500689 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 -0600690#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600691 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 -0600692 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500693
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600694 png_uint_32 uint_x, uint_y;
695
Andreas Dilger47a0c421997-05-16 02:46:07 -0500696 png_debug(1, "in png_handle_cHRM\n");
697
Guy Schalnate5a37791996-06-05 15:50:50 -0500698 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600699 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600700 else if (png_ptr->mode & PNG_HAVE_IDAT)
701 {
702 png_warning(png_ptr, "Invalid cHRM after IDAT");
703 png_crc_finish(png_ptr, length);
704 return;
705 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500706 else if (png_ptr->mode & PNG_HAVE_PLTE)
707 /* Should be an error, but we can cope with it */
708 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600709
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600710 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600711#if defined(PNG_READ_sRGB_SUPPORTED)
712 && !(info_ptr->valid & PNG_INFO_sRGB)
713#endif
714 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600715 {
716 png_warning(png_ptr, "Duplicate cHRM chunk");
717 png_crc_finish(png_ptr, length);
718 return;
719 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500720
Guy Schalnat0d580581995-07-20 02:43:20 -0500721 if (length != 32)
722 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600723 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600724 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600725 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500726 }
727
728 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600729 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500730
731 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600732 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600733
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600734 if (uint_x > 80000L || uint_y > 80000L ||
735 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600736 {
737 png_warning(png_ptr, "Invalid cHRM white point");
738 png_crc_finish(png_ptr, 24);
739 return;
740 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600741 int_x_white = (png_fixed_point)uint_x;
742 int_y_white = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500743
744 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600745 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500746
747 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600748 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600749
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600750 if (uint_x > 80000L || uint_y > 80000L ||
751 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600752 {
753 png_warning(png_ptr, "Invalid cHRM red point");
754 png_crc_finish(png_ptr, 16);
755 return;
756 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600757 int_x_red = (png_fixed_point)uint_x;
758 int_y_red = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500759
760 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600761 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500762
763 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600764 uint_y = png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600765
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600766 if (uint_x > 80000L || uint_y > 80000L ||
767 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600768 {
769 png_warning(png_ptr, "Invalid cHRM green point");
770 png_crc_finish(png_ptr, 8);
771 return;
772 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600773 int_x_green = (png_fixed_point)uint_x;
774 int_y_green = (png_fixed_point)uint_y;
Guy Schalnat0d580581995-07-20 02:43:20 -0500775
776 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600777 uint_x = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500778
779 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600780 uint_y = png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500781
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600782 if (uint_x > 80000L || uint_y > 80000L ||
783 uint_x + uint_y > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600784 {
785 png_warning(png_ptr, "Invalid cHRM blue point");
786 png_crc_finish(png_ptr, 0);
787 return;
788 }
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600789 int_x_blue = (png_fixed_point)uint_x;
790 int_y_blue = (png_fixed_point)uint_y;
791
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600792#ifdef PNG_FLOATING_POINT_SUPPORTED
793 white_x = (float)int_x_white / (float)100000.0;
794 white_y = (float)int_y_white / (float)100000.0;
795 red_x = (float)int_x_red / (float)100000.0;
796 red_y = (float)int_y_red / (float)100000.0;
797 green_x = (float)int_x_green / (float)100000.0;
798 green_y = (float)int_y_green / (float)100000.0;
799 blue_x = (float)int_x_blue / (float)100000.0;
800 blue_y = (float)int_y_blue / (float)100000.0;
801#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600802
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600803#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600804 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600805 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600806 if (abs(int_x_white - 31270L) > 1000 ||
807 abs(int_y_white - 32900L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500808 abs(int_x_red - 64000L) > 1000 ||
809 abs(int_y_red - 33000L) > 1000 ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600810 abs(int_x_green - 30000L) > 1000 ||
811 abs(int_y_green - 60000L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500812 abs(int_x_blue - 15000L) > 1000 ||
813 abs(int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600814 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600815
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600816 png_warning(png_ptr,
817 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500818#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600819#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600820 fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
821 white_x, white_y, red_x, red_y);
822 fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
823 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600824#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600825 fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600826 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600827 fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600828 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600829#endif
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500830#endif /* PNG_NO_CONSOLE_IO */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600831 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600832 png_crc_finish(png_ptr, 0);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600833 return;
834 }
835#endif /* PNG_READ_sRGB_SUPPORTED */
836
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600837#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500838 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600839 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600840#endif
841#ifdef PNG_FIXED_POINT_SUPPORTED
842 png_set_cHRM_fixed(png_ptr, info_ptr,
843 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
844 int_y_green, int_x_blue, int_y_blue);
845#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600846 if (png_crc_finish(png_ptr, 0))
847 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500848}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500849#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500850
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600851#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500852void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600853png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
854{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600855 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600856 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600857
858 png_debug(1, "in png_handle_sRGB\n");
859
860 if (!(png_ptr->mode & PNG_HAVE_IHDR))
861 png_error(png_ptr, "Missing IHDR before sRGB");
862 else if (png_ptr->mode & PNG_HAVE_IDAT)
863 {
864 png_warning(png_ptr, "Invalid sRGB after IDAT");
865 png_crc_finish(png_ptr, length);
866 return;
867 }
868 else if (png_ptr->mode & PNG_HAVE_PLTE)
869 /* Should be an error, but we can cope with it */
870 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600871
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600872 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600873 {
874 png_warning(png_ptr, "Duplicate sRGB chunk");
875 png_crc_finish(png_ptr, length);
876 return;
877 }
878
879 if (length != 1)
880 {
881 png_warning(png_ptr, "Incorrect sRGB chunk length");
882 png_crc_finish(png_ptr, length);
883 return;
884 }
885
886 png_crc_read(png_ptr, buf, 1);
887 if (png_crc_finish(png_ptr, 0))
888 return;
889
890 intent = buf[0];
891 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600892 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600893 {
894 png_warning(png_ptr, "Unknown sRGB intent");
895 return;
896 }
897
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600898#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600899 if ((info_ptr->valid & PNG_INFO_gAMA))
900 {
901 int igamma;
902#ifdef PNG_FIXED_POINT_SUPPORTED
903 igamma=(int)info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600904#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600905# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500906 igamma=(int)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600907# endif
908#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600909 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600910 {
911 png_warning(png_ptr,
912 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500913#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600914# ifdef PNG_FIXED_POINT_SUPPORTED
915 fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
916# else
917# ifdef PNG_FLOATING_POINT_SUPPORTED
918 fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
919# endif
920# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600921#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600922 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600923 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600924#endif /* PNG_READ_gAMA_SUPPORTED */
925
926#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500927#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600928 if (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600929 if (abs(info_ptr->int_x_white - 31270L) > 1000 ||
930 abs(info_ptr->int_y_white - 32900L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500931 abs(info_ptr->int_x_red - 64000L) > 1000 ||
932 abs(info_ptr->int_y_red - 33000L) > 1000 ||
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600933 abs(info_ptr->int_x_green - 30000L) > 1000 ||
934 abs(info_ptr->int_y_green - 60000L) > 1000 ||
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -0500935 abs(info_ptr->int_x_blue - 15000L) > 1000 ||
936 abs(info_ptr->int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600937 {
938 png_warning(png_ptr,
939 "Ignoring incorrect cHRM value when sRGB is also present");
940 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500941#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600942#endif /* PNG_READ_cHRM_SUPPORTED */
943
944 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
945}
946#endif /* PNG_READ_sRGB_SUPPORTED */
947
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600948#if defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500949void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600950png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
951/* Note: this does not properly handle chunks that are > 64K under DOS */
952{
953 png_charp chunkdata;
954 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600955 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600956 png_charp profile;
957 png_uint_32 skip = 0;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -0600958 png_uint_32 profile_size = 0;
959 png_uint_32 profile_length = 0;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600960 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600961
962 png_debug(1, "in png_handle_iCCP\n");
963
964 if (!(png_ptr->mode & PNG_HAVE_IHDR))
965 png_error(png_ptr, "Missing IHDR before iCCP");
966 else if (png_ptr->mode & PNG_HAVE_IDAT)
967 {
968 png_warning(png_ptr, "Invalid iCCP after IDAT");
969 png_crc_finish(png_ptr, length);
970 return;
971 }
972 else if (png_ptr->mode & PNG_HAVE_PLTE)
973 /* Should be an error, but we can cope with it */
974 png_warning(png_ptr, "Out of place iCCP chunk");
975
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600976 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600977 {
978 png_warning(png_ptr, "Duplicate iCCP chunk");
979 png_crc_finish(png_ptr, length);
980 return;
981 }
982
983#ifdef PNG_MAX_MALLOC_64K
984 if (length > (png_uint_32)65535L)
985 {
986 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
987 skip = length - (png_uint_32)65535L;
988 length = (png_uint_32)65535L;
989 }
990#endif
991
992 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
993 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500994 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600995
996 if (png_crc_finish(png_ptr, skip))
997 {
998 png_free(png_ptr, chunkdata);
999 return;
1000 }
1001
1002 chunkdata[slength] = 0x00;
1003
1004 for (profile = chunkdata; *profile; profile++)
1005 /* empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001006
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001007 ++profile;
1008
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001009 /* there should be at least one zero (the compression type byte)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001010 following the separator, and we should be on it */
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001011 if ( profile >= chunkdata + slength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001012 {
1013 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001014 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001015 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001016 }
1017
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001018 /* compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001019 compression_type = *profile++;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001020 if (compression_type)
1021 {
1022 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
1023 compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
1024 wrote nonzero) */
1025 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001026
1027 prefix_length = profile - chunkdata;
1028 chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001029 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001030
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001031 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001032
Glenn Randers-Pehrsondb3b88d2001-12-04 06:30:43 -06001033 if ( prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001034 {
1035 png_free(png_ptr, chunkdata);
1036 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1037 return;
1038 }
1039
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001040 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001041 pC = (png_bytep)(chunkdata+prefix_length);
1042 profile_size = ((*(pC ))<<24) |
1043 ((*(pC+1))<<16) |
1044 ((*(pC+2))<< 8) |
1045 ((*(pC+3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001046
1047 if(profile_size < profile_length)
1048 profile_length = profile_size;
1049
1050 if(profile_size > profile_length)
1051 {
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001052 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001053 png_warning(png_ptr, "Ignoring truncated iCCP profile.\n");
1054 return;
1055 }
1056
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001057 png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001058 chunkdata + prefix_length, profile_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001059 png_free(png_ptr, chunkdata);
1060}
1061#endif /* PNG_READ_iCCP_SUPPORTED */
1062
1063#if defined(PNG_READ_sPLT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001064void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001065png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1066/* Note: this does not properly handle chunks that are > 64K under DOS */
1067{
1068 png_bytep chunkdata;
1069 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001070 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001071#ifdef PNG_NO_POINTER_INDEXING
1072 png_sPLT_entryp pp;
1073#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001074 int data_length, entry_size, i;
1075 png_uint_32 skip = 0;
1076 png_size_t slength;
1077
1078 png_debug(1, "in png_handle_sPLT\n");
1079
1080 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1081 png_error(png_ptr, "Missing IHDR before sPLT");
1082 else if (png_ptr->mode & PNG_HAVE_IDAT)
1083 {
1084 png_warning(png_ptr, "Invalid sPLT after IDAT");
1085 png_crc_finish(png_ptr, length);
1086 return;
1087 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001088
1089#ifdef PNG_MAX_MALLOC_64K
1090 if (length > (png_uint_32)65535L)
1091 {
1092 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1093 skip = length - (png_uint_32)65535L;
1094 length = (png_uint_32)65535L;
1095 }
1096#endif
1097
1098 chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001099 slength = (png_size_t)length;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001100 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001101
1102 if (png_crc_finish(png_ptr, skip))
1103 {
1104 png_free(png_ptr, chunkdata);
1105 return;
1106 }
1107
1108 chunkdata[slength] = 0x00;
1109
1110 for (entry_start = chunkdata; *entry_start; entry_start++)
1111 /* empty loop to find end of name */ ;
1112 ++entry_start;
1113
1114 /* a sample depth should follow the separator, and we should be on it */
1115 if (entry_start > chunkdata + slength)
1116 {
1117 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001118 png_warning(png_ptr, "malformed sPLT chunk");
1119 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001120 }
1121
1122 new_palette.depth = *entry_start++;
1123 entry_size = (new_palette.depth == 8 ? 6 : 10);
1124 data_length = (slength - (entry_start - chunkdata));
1125
1126 /* integrity-check the data length */
1127 if (data_length % entry_size)
1128 {
1129 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001130 png_warning(png_ptr, "sPLT chunk has bad length");
1131 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001132 }
1133
1134 new_palette.nentries = data_length / entry_size;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001135 new_palette.entries = (png_sPLT_entryp)png_malloc(
1136 png_ptr, new_palette.nentries * sizeof(png_sPLT_entry));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001137
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001138#ifndef PNG_NO_POINTER_INDEXING
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001139 for (i = 0; i < new_palette.nentries; i++)
1140 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001141 png_sPLT_entryp pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001142
1143 if (new_palette.depth == 8)
1144 {
1145 pp->red = *entry_start++;
1146 pp->green = *entry_start++;
1147 pp->blue = *entry_start++;
1148 pp->alpha = *entry_start++;
1149 }
1150 else
1151 {
1152 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1153 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1154 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1155 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1156 }
1157 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1158 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001159#else
1160 pp = new_palette.entries;
1161 for (i = 0; i < new_palette.nentries; i++)
1162 {
1163
1164 if (new_palette.depth == 8)
1165 {
1166 pp[i].red = *entry_start++;
1167 pp[i].green = *entry_start++;
1168 pp[i].blue = *entry_start++;
1169 pp[i].alpha = *entry_start++;
1170 }
1171 else
1172 {
1173 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1174 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1175 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1176 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1177 }
1178 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1179 }
1180#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001181
1182 /* discard all chunk data except the name and stash that */
1183 new_palette.name = (png_charp)chunkdata;
1184
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001185 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001186
1187 png_free(png_ptr, chunkdata);
1188 png_free(png_ptr, new_palette.entries);
1189}
1190#endif /* PNG_READ_sPLT_SUPPORTED */
1191
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001192#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001193void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001194png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001195{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001196 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
1197
Andreas Dilger47a0c421997-05-16 02:46:07 -05001198 png_debug(1, "in png_handle_tRNS\n");
1199
Guy Schalnate5a37791996-06-05 15:50:50 -05001200 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1201 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001202 else if (png_ptr->mode & PNG_HAVE_IDAT)
1203 {
1204 png_warning(png_ptr, "Invalid tRNS after IDAT");
1205 png_crc_finish(png_ptr, length);
1206 return;
1207 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001208 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001209 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001210 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001211 png_crc_finish(png_ptr, length);
1212 return;
1213 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001214
Guy Schalnat0d580581995-07-20 02:43:20 -05001215 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1216 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001217 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1218 {
1219 /* Should be an error, but we can cope with it */
1220 png_warning(png_ptr, "Missing PLTE before tRNS");
1221 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001222 else if (length > (png_uint_32)png_ptr->num_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05001223 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001224 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001225 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001226 return;
1227 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001228 if (length == 0)
1229 {
1230 png_warning(png_ptr, "Zero length tRNS chunk");
1231 png_crc_finish(png_ptr, length);
1232 return;
1233 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001234
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001235 png_crc_read(png_ptr, readbuf, (png_size_t)length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001236 png_ptr->num_trans = (png_uint_16)length;
Guy Schalnat0d580581995-07-20 02:43:20 -05001237 }
1238 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1239 {
1240 png_byte buf[6];
1241
1242 if (length != 6)
1243 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001244 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001245 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001246 return;
1247 }
1248
Andreas Dilger47a0c421997-05-16 02:46:07 -05001249 png_crc_read(png_ptr, buf, (png_size_t)length);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001250 png_ptr->num_trans = 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001251 png_ptr->trans_values.red = png_get_uint_16(buf);
1252 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1253 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1254 }
1255 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
1256 {
1257 png_byte buf[6];
1258
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 }
1270 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001271 {
1272 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001273 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001274 return;
1275 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001276
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001277 if (png_crc_finish(png_ptr, 0))
1278 return;
1279
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001280 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -05001281 &(png_ptr->trans_values));
1282}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001283#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001284
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001285#if defined(PNG_READ_bKGD_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001286void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001287png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001288{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001289 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001290 png_byte buf[6];
1291
Andreas Dilger47a0c421997-05-16 02:46:07 -05001292 png_debug(1, "in png_handle_bKGD\n");
1293
Guy Schalnate5a37791996-06-05 15:50:50 -05001294 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1295 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001296 else if (png_ptr->mode & PNG_HAVE_IDAT)
1297 {
1298 png_warning(png_ptr, "Invalid bKGD after IDAT");
1299 png_crc_finish(png_ptr, length);
1300 return;
1301 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001302 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1303 !(png_ptr->mode & PNG_HAVE_PLTE))
1304 {
1305 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001306 png_crc_finish(png_ptr, length);
1307 return;
1308 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001309 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001310 {
1311 png_warning(png_ptr, "Duplicate bKGD chunk");
1312 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001313 return;
1314 }
1315
Guy Schalnat0d580581995-07-20 02:43:20 -05001316 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1317 truelen = 1;
1318 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1319 truelen = 6;
1320 else
1321 truelen = 2;
1322
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001323 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001324 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001325 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001326 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001327 return;
1328 }
1329
Andreas Dilger47a0c421997-05-16 02:46:07 -05001330 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001331 if (png_crc_finish(png_ptr, 0))
1332 return;
1333
Guy Schalnate5a37791996-06-05 15:50:50 -05001334 /* We convert the index value into RGB components so that we can allow
1335 * arbitrary RGB values for background when we have transparency, and
1336 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001337 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001338 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001339 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001340 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001341 if(info_ptr->num_palette)
1342 {
1343 if(buf[0] > info_ptr->num_palette)
1344 {
1345 png_warning(png_ptr, "Incorrect bKGD chunk index value");
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001346 return;
1347 }
1348 png_ptr->background.red =
1349 (png_uint_16)png_ptr->palette[buf[0]].red;
1350 png_ptr->background.green =
1351 (png_uint_16)png_ptr->palette[buf[0]].green;
1352 png_ptr->background.blue =
1353 (png_uint_16)png_ptr->palette[buf[0]].blue;
1354 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001355 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001356 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001357 {
1358 png_ptr->background.red =
1359 png_ptr->background.green =
1360 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001361 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001362 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001363 else
1364 {
1365 png_ptr->background.red = png_get_uint_16(buf);
1366 png_ptr->background.green = png_get_uint_16(buf + 2);
1367 png_ptr->background.blue = png_get_uint_16(buf + 4);
1368 }
1369
Andreas Dilger47a0c421997-05-16 02:46:07 -05001370 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001371}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001372#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001373
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001374#if defined(PNG_READ_hIST_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001375void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001376png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001377{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001378 int num, i;
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001379 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001380
Andreas Dilger47a0c421997-05-16 02:46:07 -05001381 png_debug(1, "in png_handle_hIST\n");
1382
Guy Schalnate5a37791996-06-05 15:50:50 -05001383 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1384 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001385 else if (png_ptr->mode & PNG_HAVE_IDAT)
1386 {
1387 png_warning(png_ptr, "Invalid hIST after IDAT");
1388 png_crc_finish(png_ptr, length);
1389 return;
1390 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001391 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1392 {
1393 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001394 png_crc_finish(png_ptr, length);
1395 return;
1396 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001397 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001398 {
1399 png_warning(png_ptr, "Duplicate hIST chunk");
1400 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001401 return;
1402 }
1403
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001404 num = (int)length / 2 ;
1405 if (num != png_ptr->num_palette)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001406 {
1407 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001408 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001409 return;
1410 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001411
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001412 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001413 {
1414 png_byte buf[2];
1415
1416 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001417 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001418 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001419
1420 if (png_crc_finish(png_ptr, 0))
1421 return;
1422
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001423 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001424}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001425#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001426
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001427#if defined(PNG_READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001428void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001429png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001430{
1431 png_byte buf[9];
1432 png_uint_32 res_x, res_y;
1433 int unit_type;
1434
Andreas Dilger47a0c421997-05-16 02:46:07 -05001435 png_debug(1, "in png_handle_pHYs\n");
1436
Guy Schalnate5a37791996-06-05 15:50:50 -05001437 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001438 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001439 else if (png_ptr->mode & PNG_HAVE_IDAT)
1440 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001441 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001442 png_crc_finish(png_ptr, length);
1443 return;
1444 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001445 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001446 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001447 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001448 png_crc_finish(png_ptr, length);
1449 return;
1450 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001451
Guy Schalnat0d580581995-07-20 02:43:20 -05001452 if (length != 9)
1453 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001454 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001455 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001456 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001457 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001458
1459 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001460 if (png_crc_finish(png_ptr, 0))
1461 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001462
1463 res_x = png_get_uint_32(buf);
1464 res_y = png_get_uint_32(buf + 4);
1465 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001466 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001467}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001468#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001469
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001470#if defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001471void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001472png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001473{
1474 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001475 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001476 int unit_type;
1477
Andreas Dilger47a0c421997-05-16 02:46:07 -05001478 png_debug(1, "in png_handle_oFFs\n");
1479
Guy Schalnate5a37791996-06-05 15:50:50 -05001480 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1481 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001482 else if (png_ptr->mode & PNG_HAVE_IDAT)
1483 {
1484 png_warning(png_ptr, "Invalid oFFs after IDAT");
1485 png_crc_finish(png_ptr, length);
1486 return;
1487 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001488 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001489 {
1490 png_warning(png_ptr, "Duplicate oFFs chunk");
1491 png_crc_finish(png_ptr, length);
1492 return;
1493 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001494
Guy Schalnat0d580581995-07-20 02:43:20 -05001495 if (length != 9)
1496 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001497 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001498 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001499 return;
1500 }
1501
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001502 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001503 if (png_crc_finish(png_ptr, 0))
1504 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001505
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001506 offset_x = png_get_int_32(buf);
1507 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001508 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001509 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1510}
1511#endif
1512
1513#if defined(PNG_READ_pCAL_SUPPORTED)
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001514/* read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001515void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001516png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1517{
1518 png_charp purpose;
1519 png_int_32 X0, X1;
1520 png_byte type, nparams;
1521 png_charp buf, units, endptr;
1522 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001523 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001524 int i;
1525
1526 png_debug(1, "in png_handle_pCAL\n");
1527
1528 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1529 png_error(png_ptr, "Missing IHDR before pCAL");
1530 else if (png_ptr->mode & PNG_HAVE_IDAT)
1531 {
1532 png_warning(png_ptr, "Invalid pCAL after IDAT");
1533 png_crc_finish(png_ptr, length);
1534 return;
1535 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001536 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001537 {
1538 png_warning(png_ptr, "Duplicate pCAL chunk");
1539 png_crc_finish(png_ptr, length);
1540 return;
1541 }
1542
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001543 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
Andreas Dilger47a0c421997-05-16 02:46:07 -05001544 length + 1);
1545 purpose = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001546 slength = (png_size_t)length;
1547 png_crc_read(png_ptr, (png_bytep)purpose, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001548
1549 if (png_crc_finish(png_ptr, 0))
1550 {
1551 png_free(png_ptr, purpose);
1552 return;
1553 }
1554
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001555 purpose[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001556
1557 png_debug(3, "Finding end of pCAL purpose string\n");
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001558 for (buf = purpose; *buf; buf++)
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001559 /* empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001560
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001561 endptr = purpose + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562
1563 /* We need to have at least 12 bytes after the purpose string
1564 in order to get the parameter information. */
1565 if (endptr <= buf + 12)
1566 {
1567 png_warning(png_ptr, "Invalid pCAL data");
1568 png_free(png_ptr, purpose);
1569 return;
1570 }
1571
1572 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1573 X0 = png_get_int_32((png_bytep)buf+1);
1574 X1 = png_get_int_32((png_bytep)buf+5);
1575 type = buf[9];
1576 nparams = buf[10];
1577 units = buf + 11;
1578
1579 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1580 /* Check that we have the right number of parameters for known
1581 equation types. */
1582 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1583 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1584 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1585 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1586 {
1587 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
1588 png_free(png_ptr, purpose);
1589 return;
1590 }
1591 else if (type >= PNG_EQUATION_LAST)
1592 {
1593 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1594 }
1595
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001596 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001597 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001598
1599 png_debug(3, "Allocating pCAL parameters array\n");
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001600 params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams
1601 *sizeof(png_charp))) ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001602
1603 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001604 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001605 {
1606 buf++; /* Skip the null string terminator from previous parameter. */
1607
1608 png_debug1(3, "Reading pCAL parameter %d\n", i);
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001609 for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001610 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001611
1612 /* Make sure we haven't run out of data yet */
1613 if (buf > endptr)
1614 {
1615 png_warning(png_ptr, "Invalid pCAL data");
1616 png_free(png_ptr, purpose);
1617 png_free(png_ptr, params);
1618 return;
1619 }
1620 }
1621
1622 png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
1623 units, params);
1624
1625 png_free(png_ptr, purpose);
1626 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001627}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001628#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001629
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001630#if defined(PNG_READ_sCAL_SUPPORTED)
1631/* read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001632void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001633png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1634{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001635 png_charp buffer, ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001636#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001637 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001638 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001639#else
1640#ifdef PNG_FIXED_POINT_SUPPORTED
1641 png_charp swidth, sheight;
1642#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001643#endif
1644 png_size_t slength;
1645
1646 png_debug(1, "in png_handle_sCAL\n");
1647
1648 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1649 png_error(png_ptr, "Missing IHDR before sCAL");
1650 else if (png_ptr->mode & PNG_HAVE_IDAT)
1651 {
1652 png_warning(png_ptr, "Invalid sCAL after IDAT");
1653 png_crc_finish(png_ptr, length);
1654 return;
1655 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001656 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001657 {
1658 png_warning(png_ptr, "Duplicate sCAL chunk");
1659 png_crc_finish(png_ptr, length);
1660 return;
1661 }
1662
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001663 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001664 length + 1);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001665 buffer = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001666 slength = (png_size_t)length;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001667 png_crc_read(png_ptr, (png_bytep)buffer, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001668
1669 if (png_crc_finish(png_ptr, 0))
1670 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001671 png_free(png_ptr, buffer);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001672 return;
1673 }
1674
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001675 buffer[slength] = 0x00; /* null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001676
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001677 ep = buffer + 1; /* skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001678
1679#ifdef PNG_FLOATING_POINT_SUPPORTED
1680 width = strtod(ep, &vp);
1681 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001682 {
1683 png_warning(png_ptr, "malformed width string in sCAL chunk");
1684 return;
1685 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001686#else
1687#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001688 swidth = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1);
1689 png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001690#endif
1691#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001692
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001693 for (ep = buffer; *ep; ep++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001694 /* empty loop */ ;
1695 ep++;
1696
1697#ifdef PNG_FLOATING_POINT_SUPPORTED
1698 height = strtod(ep, &vp);
1699 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001700 {
1701 png_warning(png_ptr, "malformed height string in sCAL chunk");
1702 return;
1703 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001704#else
1705#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001706 sheight = (png_charp)png_malloc(png_ptr, png_strlen(ep) + 1);
1707 png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001708#endif
1709#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001710
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001711 if (buffer + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001712#ifdef PNG_FLOATING_POINT_SUPPORTED
1713 || width <= 0. || height <= 0.
1714#endif
1715 )
1716 {
1717 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001718 png_free(png_ptr, buffer);
1719#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001720 png_free(png_ptr, swidth);
1721 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001722#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001723 return;
1724 }
1725
1726
1727#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001728 png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
1729#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001730#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001731 png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
1732#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001733#endif
1734
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001735 png_free(png_ptr, buffer);
1736#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1737 png_free(png_ptr, swidth);
1738 png_free(png_ptr, sheight);
1739#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001740}
1741#endif
1742
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001743#if defined(PNG_READ_tIME_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001744void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001745png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001746{
1747 png_byte buf[7];
1748 png_time mod_time;
1749
Andreas Dilger47a0c421997-05-16 02:46:07 -05001750 png_debug(1, "in png_handle_tIME\n");
1751
Guy Schalnate5a37791996-06-05 15:50:50 -05001752 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001753 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001754 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001755 {
1756 png_warning(png_ptr, "Duplicate tIME chunk");
1757 png_crc_finish(png_ptr, length);
1758 return;
1759 }
1760
1761 if (png_ptr->mode & PNG_HAVE_IDAT)
1762 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001763
Guy Schalnat0d580581995-07-20 02:43:20 -05001764 if (length != 7)
1765 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001766 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001767 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001768 return;
1769 }
1770
1771 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001772 if (png_crc_finish(png_ptr, 0))
1773 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001774
1775 mod_time.second = buf[6];
1776 mod_time.minute = buf[5];
1777 mod_time.hour = buf[4];
1778 mod_time.day = buf[3];
1779 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001780 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001781
Andreas Dilger47a0c421997-05-16 02:46:07 -05001782 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001783}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001784#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001785
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001786#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001788void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001789png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001790{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001791 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001792 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001793 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001794 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001795 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001796
1797 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001798
Guy Schalnate5a37791996-06-05 15:50:50 -05001799 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1800 png_error(png_ptr, "Missing IHDR before tEXt");
1801
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001802 if (png_ptr->mode & PNG_HAVE_IDAT)
1803 png_ptr->mode |= PNG_AFTER_IDAT;
1804
Andreas Dilger47a0c421997-05-16 02:46:07 -05001805#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001806 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001807 {
1808 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001809 skip = length - (png_uint_32)65535L;
1810 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001811 }
1812#endif
1813
1814 key = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001815 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001816 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001817
1818 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001819 {
1820 png_free(png_ptr, key);
1821 return;
1822 }
1823
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001824 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001825
1826 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001827 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001828
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001829 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001830 text++;
1831
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001832 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001833 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1834 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001835#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001836 text_ptr->lang = NULL;
1837 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001838 text_ptr->itxt_length = 0;
1839#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001840 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001841 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001842
1843 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1844
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -05001845 png_free(png_ptr, key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001846 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001847}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001848#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001849
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001850#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001851/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001852void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001853png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001854{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001855 png_textp text_ptr;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001856 png_charp chunkdata;
Guy Schalnat6d764711995-12-19 03:22:19 -06001857 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001858 int comp_type;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001859 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001860
1861 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001862 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1863 png_error(png_ptr, "Missing IHDR before zTXt");
1864
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001865 if (png_ptr->mode & PNG_HAVE_IDAT)
1866 png_ptr->mode |= PNG_AFTER_IDAT;
1867
Andreas Dilger47a0c421997-05-16 02:46:07 -05001868#ifdef PNG_MAX_MALLOC_64K
1869 /* We will no doubt have problems with chunks even half this size, but
1870 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001871 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001872 {
1873 png_warning(png_ptr,"zTXt chunk too large to fit in memory");
1874 png_crc_finish(png_ptr, length);
1875 return;
1876 }
1877#endif
1878
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001879 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001880 slength = (png_size_t)length;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001881 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001882 if (png_crc_finish(png_ptr, 0))
1883 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001884 png_free(png_ptr, chunkdata);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001885 return;
1886 }
1887
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001888 chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001889
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001890 for (text = chunkdata; *text; text++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001891 /* empty loop */ ;
1892
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001893 /* zTXt must have some text after the chunkdataword */
1894 if (text == chunkdata + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001895 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001896 comp_type = PNG_TEXT_COMPRESSION_NONE;
Guy Schalnat69b14481996-01-10 02:56:49 -06001897 png_warning(png_ptr, "Zero length zTXt chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001898 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001899 else
Guy Schalnat0d580581995-07-20 02:43:20 -05001900 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001901 comp_type = *(++text);
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06001902 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
1903 {
1904 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
1905 comp_type = PNG_TEXT_COMPRESSION_zTXt;
1906 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001907 text++; /* skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05001908 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001909 prefix_len = text - chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05001910
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001911 chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001912 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001913
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001914 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001915 text_ptr->compression = comp_type;
1916 text_ptr->key = chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001917#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001918 text_ptr->lang = NULL;
1919 text_ptr->lang_key = NULL;
1920 text_ptr->itxt_length = 0;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001921#endif
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001922 text_ptr->text = chunkdata + prefix_len;
1923 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001924
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001925 png_set_text(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001926
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001927 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001928 png_free(png_ptr, chunkdata);
1929}
1930#endif
1931
1932#if defined(PNG_READ_iTXt_SUPPORTED)
1933/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001934void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001935png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1936{
1937 png_textp text_ptr;
1938 png_charp chunkdata;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001939 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001940 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001941 int comp_type = 0;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001942 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001943
1944 png_debug(1, "in png_handle_iTXt\n");
1945
1946 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1947 png_error(png_ptr, "Missing IHDR before iTXt");
1948
1949 if (png_ptr->mode & PNG_HAVE_IDAT)
1950 png_ptr->mode |= PNG_AFTER_IDAT;
1951
1952#ifdef PNG_MAX_MALLOC_64K
1953 /* We will no doubt have problems with chunks even half this size, but
1954 there is no hard and fast rule to tell us where to stop. */
1955 if (length > (png_uint_32)65535L)
1956 {
1957 png_warning(png_ptr,"iTXt chunk too large to fit in memory");
1958 png_crc_finish(png_ptr, length);
1959 return;
1960 }
1961#endif
1962
1963 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001964 slength = (png_size_t)length;
1965 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001966 if (png_crc_finish(png_ptr, 0))
1967 {
1968 png_free(png_ptr, chunkdata);
1969 return;
1970 }
1971
1972 chunkdata[slength] = 0x00;
1973
1974 for (lang = chunkdata; *lang; lang++)
1975 /* empty loop */ ;
1976 lang++; /* skip NUL separator */
1977
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001978 /* iTXt must have a language tag (possibly empty), two compression bytes,
1979 translated keyword (possibly empty), and possibly some text after the
1980 keyword */
1981
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001982 if (lang >= chunkdata + slength)
1983 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001984 comp_flag = PNG_TEXT_COMPRESSION_NONE;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001985 png_warning(png_ptr, "Zero length iTXt chunk");
1986 }
1987 else
1988 {
1989 comp_flag = *lang++;
1990 comp_type = *lang++;
1991 }
1992
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001993 for (lang_key = lang; *lang_key; lang_key++)
1994 /* empty loop */ ;
1995 lang_key++; /* skip NUL separator */
1996
1997 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001998 /* empty loop */ ;
1999 text++; /* skip NUL separator */
2000
2001 prefix_len = text - chunkdata;
2002
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002003 key=chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002004 if (comp_flag)
2005 chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002006 (size_t)length, prefix_len, &data_len);
2007 else
2008 data_len=png_strlen(chunkdata + prefix_len);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002009 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002010 text_ptr->compression = (int)comp_flag + 1;
2011 text_ptr->lang_key = chunkdata+(lang_key-key);
2012 text_ptr->lang = chunkdata+(lang-key);
2013 text_ptr->itxt_length = data_len;
2014 text_ptr->text_length = 0;
2015 text_ptr->key = chunkdata;
2016 text_ptr->text = chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002017
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002018 png_set_text(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002019
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002020 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002021 png_free(png_ptr, chunkdata);
2022}
2023#endif
2024
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002025/* This function is called when we haven't found a handler for a
2026 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002027 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2028 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2029 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002030void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002031png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2032{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002033 png_uint_32 skip = 0;
2034
Andreas Dilger47a0c421997-05-16 02:46:07 -05002035 png_debug(1, "in png_handle_unknown\n");
2036
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002037 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002038 {
2039#ifdef PNG_USE_LOCAL_ARRAYS
2040 PNG_IDAT;
2041#endif
2042 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
2043 png_ptr->mode |= PNG_AFTER_IDAT;
2044 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002045
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002046 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
2047
2048 if (!(png_ptr->chunk_name[0] & 0x20))
2049 {
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002050#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002051 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2052 HANDLE_CHUNK_ALWAYS
2053#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002054 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002055#endif
2056 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002057#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002058 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002059 }
2060
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002061#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
2062 if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
2063 {
2064 png_unknown_chunk chunk;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002065
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002066#ifdef PNG_MAX_MALLOC_64K
2067 if (length > (png_uint_32)65535L)
2068 {
2069 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2070 skip = length - (png_uint_32)65535L;
2071 length = (png_uint_32)65535L;
2072 }
2073#endif
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002074 png_strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002075 chunk.data = (png_bytep)png_malloc(png_ptr, length);
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002076 chunk.size = (png_size_t)length;
2077 png_crc_read(png_ptr, (png_bytep)chunk.data, length);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002078#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002079 if(png_ptr->read_user_chunk_fn != NULL)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002080 {
2081 /* callback to user unknown chunk handler */
2082 if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0)
2083 {
2084 if (!(png_ptr->chunk_name[0] & 0x20))
2085 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2086 HANDLE_CHUNK_ALWAYS)
2087 png_chunk_error(png_ptr, "unknown critical chunk");
2088 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
2089 }
2090 }
2091 else
2092#endif
2093 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002094 png_free(png_ptr, chunk.data);
2095 }
2096 else
2097#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002098 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002099
2100 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002101
2102#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
Glenn Randers-Pehrsone68f5a32001-05-14 09:20:53 -05002103 info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002104#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002105}
2106
2107/* This function is called to verify that a chunk name is valid.
2108 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002109 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002110 functions to handle unknown critical chunks after we check that
2111 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002112
2113#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
2114
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002115void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002116png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2117{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002118 png_debug(1, "in png_check_chunk_name\n");
2119 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
2120 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002121 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002122 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002123 }
2124}
2125
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002126/* Combines the row recently read in with the existing pixels in the
2127 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002128 This routine also handles the two methods of progressive display
2129 of interlaced images, depending on the mask value.
2130 The mask value describes which pixels are to be combined with
2131 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002132 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002133 a zero indicates the pixel is to be skipped. This is in addition
2134 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002135 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002136#ifndef PNG_HAVE_ASSEMBLER_COMBINE_ROW
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002137void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002138png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002139{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002140 png_debug(1,"in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002141 if (mask == 0xff)
2142 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002143 png_memcpy(row, png_ptr->row_buf + 1,
Guy Schalnat0d580581995-07-20 02:43:20 -05002144 (png_size_t)((png_ptr->width *
2145 png_ptr->row_info.pixel_depth + 7) >> 3));
2146 }
2147 else
2148 {
2149 switch (png_ptr->row_info.pixel_depth)
2150 {
2151 case 1:
2152 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002153 png_bytep sp = png_ptr->row_buf + 1;
2154 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002155 int s_inc, s_start, s_end;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002156 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002157 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002158 png_uint_32 i;
2159 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002160
Andreas Dilger47a0c421997-05-16 02:46:07 -05002161#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2162 if (png_ptr->transformations & PNG_PACKSWAP)
2163 {
2164 s_start = 0;
2165 s_end = 7;
2166 s_inc = 1;
2167 }
2168 else
2169#endif
2170 {
2171 s_start = 7;
2172 s_end = 0;
2173 s_inc = -1;
2174 }
2175
2176 shift = s_start;
2177
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002178 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002179 {
2180 if (m & mask)
2181 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002182 int value;
2183
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002184 value = (*sp >> shift) & 0x01;
Guy Schalnat0d580581995-07-20 02:43:20 -05002185 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002186 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002187 }
2188
Andreas Dilger47a0c421997-05-16 02:46:07 -05002189 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002190 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002191 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002192 sp++;
2193 dp++;
2194 }
2195 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002196 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002197
2198 if (m == 1)
2199 m = 0x80;
2200 else
2201 m >>= 1;
2202 }
2203 break;
2204 }
2205 case 2:
2206 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002207 png_bytep sp = png_ptr->row_buf + 1;
2208 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002209 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002210 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002211 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002212 png_uint_32 i;
2213 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002214 int value;
2215
Andreas Dilger47a0c421997-05-16 02:46:07 -05002216#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2217 if (png_ptr->transformations & PNG_PACKSWAP)
2218 {
2219 s_start = 0;
2220 s_end = 6;
2221 s_inc = 2;
2222 }
2223 else
2224#endif
2225 {
2226 s_start = 6;
2227 s_end = 0;
2228 s_inc = -2;
2229 }
2230
2231 shift = s_start;
2232
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002233 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002234 {
2235 if (m & mask)
2236 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002237 value = (*sp >> shift) & 0x03;
Guy Schalnat0d580581995-07-20 02:43:20 -05002238 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002239 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002240 }
2241
Andreas Dilger47a0c421997-05-16 02:46:07 -05002242 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002243 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002244 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002245 sp++;
2246 dp++;
2247 }
2248 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002249 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002250 if (m == 1)
2251 m = 0x80;
2252 else
2253 m >>= 1;
2254 }
2255 break;
2256 }
2257 case 4:
2258 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002259 png_bytep sp = png_ptr->row_buf + 1;
2260 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002261 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002262 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002263 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002264 png_uint_32 i;
2265 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002266 int value;
2267
Andreas Dilger47a0c421997-05-16 02:46:07 -05002268#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2269 if (png_ptr->transformations & PNG_PACKSWAP)
2270 {
2271 s_start = 0;
2272 s_end = 4;
2273 s_inc = 4;
2274 }
2275 else
2276#endif
2277 {
2278 s_start = 4;
2279 s_end = 0;
2280 s_inc = -4;
2281 }
2282 shift = s_start;
2283
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002284 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002285 {
2286 if (m & mask)
2287 {
2288 value = (*sp >> shift) & 0xf;
2289 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002290 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002291 }
2292
Andreas Dilger47a0c421997-05-16 02:46:07 -05002293 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002294 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002295 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002296 sp++;
2297 dp++;
2298 }
2299 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002300 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002301 if (m == 1)
2302 m = 0x80;
2303 else
2304 m >>= 1;
2305 }
2306 break;
2307 }
2308 default:
2309 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002310 png_bytep sp = png_ptr->row_buf + 1;
2311 png_bytep dp = row;
2312 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2313 png_uint_32 i;
2314 png_uint_32 row_width = png_ptr->width;
2315 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002316
Guy Schalnat0d580581995-07-20 02:43:20 -05002317
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002318 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002319 {
2320 if (m & mask)
2321 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002322 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002323 }
2324
2325 sp += pixel_bytes;
2326 dp += pixel_bytes;
2327
2328 if (m == 1)
2329 m = 0x80;
2330 else
2331 m >>= 1;
2332 }
2333 break;
2334 }
2335 }
2336 }
2337}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002338#endif /* !PNG_HAVE_ASSEMBLER_COMBINE_ROW */
Guy Schalnat0d580581995-07-20 02:43:20 -05002339
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002340#ifdef PNG_READ_INTERLACING_SUPPORTED
2341#ifndef PNG_HAVE_ASSEMBLER_READ_INTERLACE /* else in pngvcrd.c, pnggccrd.c */
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002342/* OLD pre-1.0.9 interface:
2343void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2344 png_uint_32 transformations)
2345 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002346void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002347png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002348{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002349 png_row_infop row_info = &(png_ptr->row_info);
2350 png_bytep row = png_ptr->row_buf + 1;
2351 int pass = png_ptr->pass;
2352 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002353#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002354 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002355 /* offset to next interlace block */
2356 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002357#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002358
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002359 png_debug(1,"in png_do_read_interlace (stock C version)\n");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002360 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002361 {
2362 png_uint_32 final_width;
2363
2364 final_width = row_info->width * png_pass_inc[pass];
2365
2366 switch (row_info->pixel_depth)
2367 {
2368 case 1:
2369 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002370 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2371 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002372 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002373 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002374 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002375 png_byte v;
2376 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002377 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002378
Andreas Dilger47a0c421997-05-16 02:46:07 -05002379#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2380 if (transformations & PNG_PACKSWAP)
2381 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002382 sshift = (int)((row_info->width + 7) & 0x07);
2383 dshift = (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002384 s_start = 7;
2385 s_end = 0;
2386 s_inc = -1;
2387 }
2388 else
2389#endif
2390 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002391 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2392 dshift = 7 - (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002393 s_start = 0;
2394 s_end = 7;
2395 s_inc = 1;
2396 }
2397
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002398 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002399 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002400 v = (png_byte)((*sp >> sshift) & 0x01);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002401 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002402 {
2403 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2404 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002405 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002406 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002407 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002408 dp--;
2409 }
2410 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002411 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002412 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002413 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002414 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002415 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002416 sp--;
2417 }
2418 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002419 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002420 }
2421 break;
2422 }
2423 case 2:
2424 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002425 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2426 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002427 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002428 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002429 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002430 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002431
Andreas Dilger47a0c421997-05-16 02:46:07 -05002432#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2433 if (transformations & PNG_PACKSWAP)
2434 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002435 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2436 dshift = (int)(((final_width + 3) & 0x03) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002437 s_start = 6;
2438 s_end = 0;
2439 s_inc = -2;
2440 }
2441 else
2442#endif
2443 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002444 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2445 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002446 s_start = 0;
2447 s_end = 6;
2448 s_inc = 2;
2449 }
2450
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002451 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002452 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002453 png_byte v;
2454 int j;
2455
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002456 v = (png_byte)((*sp >> sshift) & 0x03);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002457 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002458 {
2459 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002460 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002461 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002462 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002463 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002464 dp--;
2465 }
2466 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002467 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002468 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002469 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002470 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002471 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002472 sp--;
2473 }
2474 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002475 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002476 }
2477 break;
2478 }
2479 case 4:
2480 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002481 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2482 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002483 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002484 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002485 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002486 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002487
Andreas Dilger47a0c421997-05-16 02:46:07 -05002488#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2489 if (transformations & PNG_PACKSWAP)
2490 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002491 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2492 dshift = (int)(((final_width + 1) & 0x01) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002493 s_start = 4;
2494 s_end = 0;
2495 s_inc = -4;
2496 }
2497 else
2498#endif
2499 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002500 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2501 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002502 s_start = 0;
2503 s_end = 4;
2504 s_inc = 4;
2505 }
2506
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002507 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002508 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002509 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002510 int j;
2511
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002512 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002513 {
2514 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002515 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002516 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002517 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002518 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002519 dp--;
2520 }
2521 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002522 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002523 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002524 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002525 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002526 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002527 sp--;
2528 }
2529 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002530 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002531 }
2532 break;
2533 }
2534 default:
2535 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002536 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
2537 png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
2538 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002539
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002540 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002541 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002542
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002543 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002544 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002545 png_byte v[8];
2546 int j;
2547
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002548 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002549 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002550 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002551 png_memcpy(dp, v, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002552 dp -= pixel_bytes;
2553 }
2554 sp -= pixel_bytes;
2555 }
2556 break;
2557 }
2558 }
2559 row_info->width = final_width;
2560 row_info->rowbytes = ((final_width *
2561 (png_uint_32)row_info->pixel_depth + 7) >> 3);
2562 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002563#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
Glenn Randers-Pehrsone68f5a32001-05-14 09:20:53 -05002564 transformations = transformations; /* silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002565#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002566}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002567#endif /* !PNG_HAVE_ASSEMBLER_READ_INTERLACE */
2568#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05002569
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002570#ifndef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002571void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002572png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002573 png_bytep prev_row, int filter)
2574{
2575 png_debug(1, "in png_read_filter_row\n");
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05002576 png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002577 switch (filter)
2578 {
2579 case PNG_FILTER_VALUE_NONE:
2580 break;
2581 case PNG_FILTER_VALUE_SUB:
2582 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002583 png_uint_32 i;
2584 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002585 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002586 png_bytep rp = row + bpp;
2587 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002588
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002589 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002590 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002591 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2592 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002593 }
2594 break;
2595 }
2596 case PNG_FILTER_VALUE_UP:
2597 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002598 png_uint_32 i;
2599 png_uint_32 istop = row_info->rowbytes;
2600 png_bytep rp = row;
2601 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002602
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002603 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002604 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002605 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2606 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002607 }
2608 break;
2609 }
2610 case PNG_FILTER_VALUE_AVG:
2611 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002612 png_uint_32 i;
2613 png_bytep rp = row;
2614 png_bytep pp = prev_row;
2615 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002616 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002617 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002618
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002619 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002620 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002621 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002622 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002623 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002624 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002625
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002626 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002627 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002628 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002629 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002630 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002631 }
2632 break;
2633 }
2634 case PNG_FILTER_VALUE_PAETH:
2635 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002636 png_uint_32 i;
2637 png_bytep rp = row;
2638 png_bytep pp = prev_row;
2639 png_bytep lp = row;
2640 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002641 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002642 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002643
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002644 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002645 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002646 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2647 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002648 }
2649
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002650 for (i = 0; i < istop; i++) /* use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002651 {
2652 int a, b, c, pa, pb, pc, p;
2653
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002654 a = *lp++;
2655 b = *pp++;
2656 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002657
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002658 p = b - c;
2659 pc = a - c;
2660
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002661#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002662 pa = abs(p);
2663 pb = abs(pc);
2664 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002665#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002666 pa = p < 0 ? -p : p;
2667 pb = pc < 0 ? -pc : pc;
2668 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002669#endif
2670
2671 /*
2672 if (pa <= pb && pa <= pc)
2673 p = a;
2674 else if (pb <= pc)
2675 p = b;
2676 else
2677 p = c;
2678 */
2679
2680 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2681
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002682 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2683 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002684 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002685 break;
2686 }
2687 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002688 png_warning(png_ptr, "Ignoring bad adaptive filter type");
2689 *row=0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002690 break;
2691 }
2692}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002693#endif /* !PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
Guy Schalnat0d580581995-07-20 02:43:20 -05002694
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002695void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002696png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002697{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002698#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002699 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002700
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002701 /* start of interlace block */
2702 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002703
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002704 /* offset to next interlace block */
2705 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002706
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002707 /* start of interlace block in the y direction */
2708 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002709
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002710 /* offset to next interlace block in the y direction */
2711 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002712#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002713
Andreas Dilger47a0c421997-05-16 02:46:07 -05002714 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002715 png_ptr->row_number++;
2716 if (png_ptr->row_number < png_ptr->num_rows)
2717 return;
2718
2719 if (png_ptr->interlaced)
2720 {
2721 png_ptr->row_number = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002722 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002723 do
2724 {
2725 png_ptr->pass++;
2726 if (png_ptr->pass >= 7)
2727 break;
2728 png_ptr->iwidth = (png_ptr->width +
2729 png_pass_inc[png_ptr->pass] - 1 -
2730 png_pass_start[png_ptr->pass]) /
2731 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002732 png_ptr->irowbytes = ((png_ptr->iwidth *
2733 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
2734
Guy Schalnat0d580581995-07-20 02:43:20 -05002735 if (!(png_ptr->transformations & PNG_INTERLACE))
2736 {
2737 png_ptr->num_rows = (png_ptr->height +
2738 png_pass_yinc[png_ptr->pass] - 1 -
2739 png_pass_ystart[png_ptr->pass]) /
2740 png_pass_yinc[png_ptr->pass];
2741 if (!(png_ptr->num_rows))
2742 continue;
2743 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002744 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002745 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002746 } while (png_ptr->iwidth == 0);
2747
2748 if (png_ptr->pass < 7)
2749 return;
2750 }
2751
Guy Schalnate5a37791996-06-05 15:50:50 -05002752 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002753 {
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002754#ifdef PNG_USE_LOCAL_ARRAYS
2755 PNG_IDAT;
2756#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002757 char extra;
2758 int ret;
2759
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002760 png_ptr->zstream.next_out = (Byte *)&extra;
2761 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002762 for(;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05002763 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002764 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002765 {
2766 while (!png_ptr->idat_size)
2767 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002768 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002769
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002770 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002771
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002772 png_read_data(png_ptr, chunk_length, 4);
2773 png_ptr->idat_size = png_get_uint_32(chunk_length);
2774
Guy Schalnat0d580581995-07-20 02:43:20 -05002775 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002776 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002777 if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002778 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002779
2780 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002781 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2782 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002783 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002784 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2785 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2786 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002787 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002788 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002789 if (ret == Z_STREAM_END)
2790 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002791 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002792 png_ptr->idat_size)
Guy Schalnat6d764711995-12-19 03:22:19 -06002793 png_error(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002794 png_ptr->mode |= PNG_AFTER_IDAT;
2795 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002796 break;
2797 }
2798 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002799 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05002800 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05002801
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002802 if (!(png_ptr->zstream.avail_out))
Guy Schalnat6d764711995-12-19 03:22:19 -06002803 png_error(png_ptr, "Extra compressed data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002804
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002805 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002806 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002807 }
2808
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002809 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Guy Schalnat6d764711995-12-19 03:22:19 -06002810 png_error(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002811
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002812 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05002813
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002814 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002815}
2816
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002817void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002818png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002819{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002820#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002821 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002822
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002823 /* start of interlace block */
2824 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002825
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002826 /* offset to next interlace block */
2827 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002828
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002829 /* start of interlace block in the y direction */
2830 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002831
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002832 /* offset to next interlace block in the y direction */
2833 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002834#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002835
Guy Schalnat0d580581995-07-20 02:43:20 -05002836 int max_pixel_depth;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002837 png_uint_32 row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002838
Andreas Dilger47a0c421997-05-16 02:46:07 -05002839 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002840 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002841 png_init_read_transformations(png_ptr);
2842 if (png_ptr->interlaced)
2843 {
2844 if (!(png_ptr->transformations & PNG_INTERLACE))
2845 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
2846 png_pass_ystart[0]) / png_pass_yinc[0];
2847 else
2848 png_ptr->num_rows = png_ptr->height;
2849
2850 png_ptr->iwidth = (png_ptr->width +
2851 png_pass_inc[png_ptr->pass] - 1 -
2852 png_pass_start[png_ptr->pass]) /
2853 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002854
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002855 row_bytes = ((png_ptr->iwidth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002856 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002857 png_ptr->irowbytes = (png_size_t)row_bytes;
2858 if((png_uint_32)png_ptr->irowbytes != row_bytes)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002859 png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002860 }
2861 else
2862 {
2863 png_ptr->num_rows = png_ptr->height;
2864 png_ptr->iwidth = png_ptr->width;
2865 png_ptr->irowbytes = png_ptr->rowbytes + 1;
2866 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002867 max_pixel_depth = png_ptr->pixel_depth;
2868
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002869#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002870 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002871 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002872#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002873
Guy Schalnate5a37791996-06-05 15:50:50 -05002874#if defined(PNG_READ_EXPAND_SUPPORTED)
2875 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002876 {
2877 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2878 {
2879 if (png_ptr->num_trans)
2880 max_pixel_depth = 32;
2881 else
2882 max_pixel_depth = 24;
2883 }
2884 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
2885 {
2886 if (max_pixel_depth < 8)
2887 max_pixel_depth = 8;
2888 if (png_ptr->num_trans)
2889 max_pixel_depth *= 2;
2890 }
2891 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2892 {
2893 if (png_ptr->num_trans)
2894 {
2895 max_pixel_depth *= 4;
2896 max_pixel_depth /= 3;
2897 }
2898 }
2899 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002900#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002901
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002902#if defined(PNG_READ_FILLER_SUPPORTED)
2903 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05002904 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002905 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2906 max_pixel_depth = 32;
2907 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002908 {
2909 if (max_pixel_depth <= 8)
2910 max_pixel_depth = 16;
2911 else
2912 max_pixel_depth = 32;
2913 }
2914 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2915 {
2916 if (max_pixel_depth <= 32)
2917 max_pixel_depth = 32;
2918 else
2919 max_pixel_depth = 64;
2920 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002921 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002922#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002923
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002924#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002925 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
2926 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002927 if (
2928#if defined(PNG_READ_EXPAND_SUPPORTED)
2929 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
2930#endif
2931#if defined(PNG_READ_FILLER_SUPPORTED)
2932 (png_ptr->transformations & (PNG_FILLER)) ||
2933#endif
2934 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002935 {
2936 if (max_pixel_depth <= 16)
2937 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002938 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002939 max_pixel_depth = 64;
2940 }
2941 else
2942 {
2943 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06002944 {
2945 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2946 max_pixel_depth = 32;
2947 else
2948 max_pixel_depth = 24;
2949 }
2950 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2951 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002952 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002953 max_pixel_depth = 48;
2954 }
2955 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002956#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002957
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002958#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
2959defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002960 if(png_ptr->transformations & PNG_USER_TRANSFORM)
2961 {
2962 int user_pixel_depth=png_ptr->user_transform_depth*
2963 png_ptr->user_transform_channels;
2964 if(user_pixel_depth > max_pixel_depth)
2965 max_pixel_depth=user_pixel_depth;
2966 }
2967#endif
2968
Guy Schalnat0d580581995-07-20 02:43:20 -05002969 /* align the width on the next larger 8 pixels. Mainly used
2970 for interlacing */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002971 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Guy Schalnat0d580581995-07-20 02:43:20 -05002972 /* calculate the maximum bytes needed, adding a byte and a pixel
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002973 for safety's sake */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002974 row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
Guy Schalnat0d580581995-07-20 02:43:20 -05002975 1 + ((max_pixel_depth + 7) >> 3);
2976#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002977 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002978 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002979#endif
Glenn Randers-Pehrson1b8e5672001-08-25 06:46:06 -05002980 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
2981 png_ptr->row_buf = png_ptr->big_row_buf+32;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -05002982#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD)
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05002983 png_ptr->row_buf_size = row_bytes;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -05002984#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002985
2986#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002987 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002988 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002989#endif
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002990 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
2991 png_ptr->rowbytes + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002992
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002993 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002994
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05002995 png_debug1(3, "width = %lu,\n", png_ptr->width);
2996 png_debug1(3, "height = %lu,\n", png_ptr->height);
2997 png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
2998 png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
2999 png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
3000 png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05003001
Guy Schalnate5a37791996-06-05 15:50:50 -05003002 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003003}