blob: 2be3c87b87bb805a4b670e81635ffa17e6f3cf1b [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-Pehrson4766a242000-07-17 06:17:09 -05004 * libpng 1.0.8rc1 - July 17, 2000
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06006 * Copyright (c) 1998, 1999, 2000 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);
33 *endptr = (char *)nptr + (strlen(nptr) - len + 1);
34 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
177 if (comp_type == PNG_TEXT_COMPRESSION_zTXt)
178 {
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);
204 png_memcpy(text, chunkdata, prefix_size);
205 }
206
207 text[text_size - 1] = 0x00;
208
209 /* 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);
213 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);
222 png_memcpy(text + prefix_size, png_ptr->zbuf,
223 text_size - prefix_size);
224 png_memcpy(text, chunkdata, prefix_size);
225 *(text + text_size) = 0x00;
226 }
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
269 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600270
271 inflateReset(&png_ptr->zstream);
272 png_ptr->zstream.avail_in = 0;
273
274 png_free(png_ptr, chunkdata);
275 chunkdata = text;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600276 *newlength=text_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600277 }
Glenn Randers-Pehrson13944802000-06-24 07:42:42 -0500278 else /* if (comp_type != PNG_TEXT_COMPRESSION_zTXt) */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600279 {
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500280#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600281 char umsg[50];
282
283 sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
284 png_warning(png_ptr, umsg);
285#else
286 png_warning(png_ptr, "Unknown zTXt compression type");
287#endif
288
289 /* Copy what we can of the error message into the text chunk */
290 text_size = (png_size_t)(chunklength - (text - chunkdata));
291 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
292 png_memcpy(text, msg, text_size);
293 }
294
295 return chunkdata;
296}
297#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600298
Guy Schalnat0d580581995-07-20 02:43:20 -0500299/* read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500300void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600301png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500302{
303 png_byte buf[13];
304 png_uint_32 width, height;
305 int bit_depth, color_type, compression_type, filter_type;
306 int interlace_type;
307
Andreas Dilger47a0c421997-05-16 02:46:07 -0500308 png_debug(1, "in png_handle_IHDR\n");
309
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600310 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500311 png_error(png_ptr, "Out of place IHDR");
312
Guy Schalnat0d580581995-07-20 02:43:20 -0500313 /* check the length */
314 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600315 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500316
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600317 png_ptr->mode |= PNG_HAVE_IHDR;
318
Guy Schalnat0d580581995-07-20 02:43:20 -0500319 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600320 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500321
322 width = png_get_uint_32(buf);
323 height = png_get_uint_32(buf + 4);
324 bit_depth = buf[8];
325 color_type = buf[9];
326 compression_type = buf[10];
327 filter_type = buf[11];
328 interlace_type = buf[12];
329
330 /* check for width and height valid values */
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500331 if (width == 0 || width > PNG_MAX_UINT || height == 0 ||
332 height > PNG_MAX_UINT)
Guy Schalnate5a37791996-06-05 15:50:50 -0500333 png_error(png_ptr, "Invalid image size in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500334
335 /* check other values */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500336 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
337 bit_depth != 8 && bit_depth != 16)
Guy Schalnate5a37791996-06-05 15:50:50 -0500338 png_error(png_ptr, "Invalid bit depth in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500339
340 if (color_type < 0 || color_type == 1 ||
341 color_type == 5 || color_type > 6)
Guy Schalnate5a37791996-06-05 15:50:50 -0500342 png_error(png_ptr, "Invalid color type in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500343
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -0500344 if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600345 ((color_type == PNG_COLOR_TYPE_RGB ||
346 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
347 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
348 png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500349
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600350 if (interlace_type >= PNG_INTERLACE_LAST)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600351 png_error(png_ptr, "Unknown interlace method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500352
Andreas Dilger47a0c421997-05-16 02:46:07 -0500353 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600354 png_error(png_ptr, "Unknown compression method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500355
Andreas Dilger47a0c421997-05-16 02:46:07 -0500356 if (filter_type != PNG_FILTER_TYPE_BASE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600357 png_error(png_ptr, "Unknown filter method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500358
359 /* set internal variables */
360 png_ptr->width = width;
361 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600362 png_ptr->bit_depth = (png_byte)bit_depth;
363 png_ptr->interlaced = (png_byte)interlace_type;
364 png_ptr->color_type = (png_byte)color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500365
366 /* find number of channels */
367 switch (png_ptr->color_type)
368 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500369 case PNG_COLOR_TYPE_GRAY:
370 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500371 png_ptr->channels = 1;
372 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500373 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500374 png_ptr->channels = 3;
375 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500376 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500377 png_ptr->channels = 2;
378 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500379 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500380 png_ptr->channels = 4;
381 break;
382 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600383
Guy Schalnat0d580581995-07-20 02:43:20 -0500384 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600385 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600386 png_ptr->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500387 png_ptr->rowbytes = ((png_ptr->width *
388 (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500389 png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
390 png_debug1(3,"channels = %d\n", png_ptr->channels);
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -0500391 png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500392 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
393 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500394}
395
396/* read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500397void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600398png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500399{
Guy Schalnat6d764711995-12-19 03:22:19 -0600400 png_colorp palette;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600401 int num, i;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500402#ifndef PNG_NO_POINTER_INDEXING
403 png_colorp pal_ptr;
404#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500405
Andreas Dilger47a0c421997-05-16 02:46:07 -0500406 png_debug(1, "in png_handle_PLTE\n");
407
Guy Schalnate5a37791996-06-05 15:50:50 -0500408 if (!(png_ptr->mode & PNG_HAVE_IHDR))
409 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600410 else if (png_ptr->mode & PNG_HAVE_IDAT)
411 {
412 png_warning(png_ptr, "Invalid PLTE after IDAT");
413 png_crc_finish(png_ptr, length);
414 return;
415 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500416 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600417 png_error(png_ptr, "Duplicate PLTE chunk");
418
419 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500420
421#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
422 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
423 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600424 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500425 return;
426 }
427#endif
428
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500429 if (length > 768 || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500430 {
431 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
432 {
433 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600434 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500435 return;
436 }
437 else
438 {
439 png_error(png_ptr, "Invalid palette chunk");
440 }
441 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500442
443 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500444
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600445 palette = (png_colorp)png_zalloc(png_ptr, (uInt)num, sizeof (png_color));
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500446
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500447#ifndef PNG_NO_POINTER_INDEXING
448 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
449 {
450 png_byte buf[3];
451
452 png_crc_read(png_ptr, buf, 3);
453 pal_ptr->red = buf[0];
454 pal_ptr->green = buf[1];
455 pal_ptr->blue = buf[2];
456 }
457#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600458 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500459 {
460 png_byte buf[3];
461
462 png_crc_read(png_ptr, buf, 3);
463 /* don't depend upon png_color being any order */
464 palette[i].red = buf[0];
465 palette[i].green = buf[1];
466 palette[i].blue = buf[2];
467 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500468#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600469
470 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
471 whatever the normal CRC configuration tells us. However, if we
472 have an RGB image, the PLTE can be considered ancillary, so
473 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600474#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600475 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600476#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600477 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500478 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600479 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600480#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600481 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
482 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600483 /* If we don't want to use the data from an ancillary chunk,
484 we have two options: an error abort, or a warning and we
485 ignore the data in this chunk (which should be OK, since
486 it's considered ancillary for a RGB or RGBA image). */
487 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
488 {
489 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
490 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600491 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600492 }
493 else
494 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600495 png_chunk_warning(png_ptr, "CRC error");
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600496 png_zfree(png_ptr, palette);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600497 return;
498 }
499 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500500 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600501 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
502 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600503 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600504 }
505 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600506#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500507 png_ptr->palette = palette;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600508 png_ptr->num_palette = (png_uint_16)num;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500509
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500510#ifdef PNG_FREE_ME_SUPPORTED
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500511 png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
512 png_ptr->free_me |= PNG_FREE_PLTE;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500513#else
514 png_ptr->flags |= PNG_FLAG_FREE_PLTE;
515#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500516 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500517
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500518#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500519 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
520 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600521 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500522 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500523 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500524 {
525 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500526 png_ptr->num_trans = (png_uint_16)num;
527 }
528 if (info_ptr->num_trans > (png_uint_16)num)
529 {
530 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
531 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500532 }
533 }
534 }
535#endif
536
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600537}
Guy Schalnate5a37791996-06-05 15:50:50 -0500538
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500539void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600540png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
541{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500542 png_debug(1, "in png_handle_IEND\n");
543
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600544 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
545 {
546 png_error(png_ptr, "No image in file");
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -0600547
548 /* to quiet compiler warnings about unused info_ptr */
549 if (info_ptr == NULL)
550 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600551 }
552
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600553 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600554
555 if (length != 0)
556 {
557 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600558 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500559 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500560}
561
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500562#if defined(PNG_READ_gAMA_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500563void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600564png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500565{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600566 png_fixed_point igamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600567#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500568 float file_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600569#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500570 png_byte buf[4];
571
Andreas Dilger47a0c421997-05-16 02:46:07 -0500572 png_debug(1, "in png_handle_gAMA\n");
573
Guy Schalnate5a37791996-06-05 15:50:50 -0500574 if (!(png_ptr->mode & PNG_HAVE_IHDR))
575 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600576 else if (png_ptr->mode & PNG_HAVE_IDAT)
577 {
578 png_warning(png_ptr, "Invalid gAMA after IDAT");
579 png_crc_finish(png_ptr, length);
580 return;
581 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500582 else if (png_ptr->mode & PNG_HAVE_PLTE)
583 /* Should be an error, but we can cope with it */
584 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600585
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600586 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600587#if defined(PNG_READ_sRGB_SUPPORTED)
588 && !(info_ptr->valid & PNG_INFO_sRGB)
589#endif
590 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600591 {
592 png_warning(png_ptr, "Duplicate gAMA chunk");
593 png_crc_finish(png_ptr, length);
594 return;
595 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500596
Guy Schalnat0d580581995-07-20 02:43:20 -0500597 if (length != 4)
598 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600599 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600600 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500601 return;
602 }
603
604 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600605 if (png_crc_finish(png_ptr, 0))
606 return;
607
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600608 igamma = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500609 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500610 if (igamma == 0)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600611 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500612
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600613#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600614 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600615 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600616 {
617 png_warning(png_ptr,
618 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500619#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600620 fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600621#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600622 return;
623 }
624#endif /* PNG_READ_sRGB_SUPPORTED */
625
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600626#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600627 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600628# ifdef PNG_READ_GAMMA_SUPPORTED
629 png_ptr->gamma = file_gamma;
630# endif
631 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600632#endif
633#ifdef PNG_FIXED_POINT_SUPPORTED
634 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
635#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500636}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500637#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500638
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500639#if defined(PNG_READ_sBIT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500640void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600641png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500642{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500643 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600644 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600645
Andreas Dilger47a0c421997-05-16 02:46:07 -0500646 png_debug(1, "in png_handle_sBIT\n");
647
Guy Schalnat69b14481996-01-10 02:56:49 -0600648 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500649
Guy Schalnate5a37791996-06-05 15:50:50 -0500650 if (!(png_ptr->mode & PNG_HAVE_IHDR))
651 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600652 else if (png_ptr->mode & PNG_HAVE_IDAT)
653 {
654 png_warning(png_ptr, "Invalid sBIT after IDAT");
655 png_crc_finish(png_ptr, length);
656 return;
657 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500658 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600659 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500660 /* Should be an error, but we can cope with it */
661 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600662 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600663 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600664 {
665 png_warning(png_ptr, "Duplicate sBIT chunk");
666 png_crc_finish(png_ptr, length);
667 return;
668 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500669
Guy Schalnat0d580581995-07-20 02:43:20 -0500670 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600671 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500672 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500673 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500674
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600675 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500676 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600677 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600678 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600679 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500680 }
681
Andreas Dilger47a0c421997-05-16 02:46:07 -0500682 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600683 if (png_crc_finish(png_ptr, 0))
684 return;
685
Guy Schalnat0d580581995-07-20 02:43:20 -0500686 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
687 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600688 png_ptr->sig_bit.red = buf[0];
689 png_ptr->sig_bit.green = buf[1];
690 png_ptr->sig_bit.blue = buf[2];
691 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500692 }
693 else
694 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600695 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600696 png_ptr->sig_bit.red = buf[0];
697 png_ptr->sig_bit.green = buf[0];
698 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600699 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500700 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500701 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500702}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500703#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500704
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500705#if defined(PNG_READ_cHRM_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500706void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600707png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500708{
709 png_byte buf[4];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600710#ifdef PNG_FLOATING_POINT_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -0500711 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 -0600712#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600713 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 -0600714 int_y_green, int_x_blue, int_y_blue;
Guy Schalnat0d580581995-07-20 02:43:20 -0500715
Andreas Dilger47a0c421997-05-16 02:46:07 -0500716 png_debug(1, "in png_handle_cHRM\n");
717
Guy Schalnate5a37791996-06-05 15:50:50 -0500718 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600719 png_error(png_ptr, "Missing IHDR before cHRM");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600720 else if (png_ptr->mode & PNG_HAVE_IDAT)
721 {
722 png_warning(png_ptr, "Invalid cHRM after IDAT");
723 png_crc_finish(png_ptr, length);
724 return;
725 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500726 else if (png_ptr->mode & PNG_HAVE_PLTE)
727 /* Should be an error, but we can cope with it */
728 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600729
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600730 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600731#if defined(PNG_READ_sRGB_SUPPORTED)
732 && !(info_ptr->valid & PNG_INFO_sRGB)
733#endif
734 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600735 {
736 png_warning(png_ptr, "Duplicate cHRM chunk");
737 png_crc_finish(png_ptr, length);
738 return;
739 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500740
Guy Schalnat0d580581995-07-20 02:43:20 -0500741 if (length != 32)
742 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600743 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600744 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600745 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500746 }
747
748 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600749 int_x_white = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500750
751 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600752 int_y_white = (png_fixed_point)png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600753
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600754 if (int_x_white > 80000L || int_y_white > 80000L ||
755 int_x_white + int_y_white > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600756 {
757 png_warning(png_ptr, "Invalid cHRM white point");
758 png_crc_finish(png_ptr, 24);
759 return;
760 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500761
762 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600763 int_x_red = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500764
765 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600766 int_y_red = (png_fixed_point)png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600767
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600768 if (int_x_red > 80000L || int_y_red > 80000L ||
769 int_x_red + int_y_red > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600770 {
771 png_warning(png_ptr, "Invalid cHRM red point");
772 png_crc_finish(png_ptr, 16);
773 return;
774 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500775
776 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600777 int_x_green = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500778
779 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600780 int_y_green = (png_fixed_point)png_get_uint_32(buf);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600781
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600782 if (int_x_green > 80000L || int_y_green > 80000L ||
783 int_x_green + int_y_green > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600784 {
785 png_warning(png_ptr, "Invalid cHRM green point");
786 png_crc_finish(png_ptr, 8);
787 return;
788 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500789
790 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600791 int_x_blue = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500792
793 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600794 int_y_blue = (png_fixed_point)png_get_uint_32(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -0500795
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600796 if (int_x_blue > 80000L || int_y_blue > 80000L ||
797 int_x_blue + int_y_blue > 100000L)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600798 {
799 png_warning(png_ptr, "Invalid cHRM blue point");
800 png_crc_finish(png_ptr, 0);
801 return;
802 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600803#ifdef PNG_FLOATING_POINT_SUPPORTED
804 white_x = (float)int_x_white / (float)100000.0;
805 white_y = (float)int_y_white / (float)100000.0;
806 red_x = (float)int_x_red / (float)100000.0;
807 red_y = (float)int_y_red / (float)100000.0;
808 green_x = (float)int_x_green / (float)100000.0;
809 green_y = (float)int_y_green / (float)100000.0;
810 blue_x = (float)int_x_blue / (float)100000.0;
811 blue_y = (float)int_y_blue / (float)100000.0;
812#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600813
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600814#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600815 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600816 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600817 if (abs(int_x_white - 31270L) > 1000 ||
818 abs(int_y_white - 32900L) > 1000 ||
819 abs( int_x_red - 64000L) > 1000 ||
820 abs( int_y_red - 33000L) > 1000 ||
821 abs(int_x_green - 30000L) > 1000 ||
822 abs(int_y_green - 60000L) > 1000 ||
823 abs( int_x_blue - 15000L) > 1000 ||
824 abs( int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600825 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600826
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600827 png_warning(png_ptr,
828 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500829#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600830#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600831 fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
832 white_x, white_y, red_x, red_y);
833 fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
834 green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600835#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600836 fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600837 int_x_white, int_y_white, int_x_red, int_y_red);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600838 fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600839 int_x_green, int_y_green, int_x_blue, int_y_blue);
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600840#endif
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500841#endif /* PNG_NO_CONSOLE_IO */
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600842 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600843 png_crc_finish(png_ptr, 0);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600844 return;
845 }
846#endif /* PNG_READ_sRGB_SUPPORTED */
847
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600848#ifdef PNG_FLOATING_POINT_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500849 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600850 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600851#endif
852#ifdef PNG_FIXED_POINT_SUPPORTED
853 png_set_cHRM_fixed(png_ptr, info_ptr,
854 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
855 int_y_green, int_x_blue, int_y_blue);
856#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600857 if (png_crc_finish(png_ptr, 0))
858 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500859}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500860#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500861
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600862#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500863void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600864png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
865{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600866 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600867 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600868
869 png_debug(1, "in png_handle_sRGB\n");
870
871 if (!(png_ptr->mode & PNG_HAVE_IHDR))
872 png_error(png_ptr, "Missing IHDR before sRGB");
873 else if (png_ptr->mode & PNG_HAVE_IDAT)
874 {
875 png_warning(png_ptr, "Invalid sRGB after IDAT");
876 png_crc_finish(png_ptr, length);
877 return;
878 }
879 else if (png_ptr->mode & PNG_HAVE_PLTE)
880 /* Should be an error, but we can cope with it */
881 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600882
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600883 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600884 {
885 png_warning(png_ptr, "Duplicate sRGB chunk");
886 png_crc_finish(png_ptr, length);
887 return;
888 }
889
890 if (length != 1)
891 {
892 png_warning(png_ptr, "Incorrect sRGB chunk length");
893 png_crc_finish(png_ptr, length);
894 return;
895 }
896
897 png_crc_read(png_ptr, buf, 1);
898 if (png_crc_finish(png_ptr, 0))
899 return;
900
901 intent = buf[0];
902 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600903 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600904 {
905 png_warning(png_ptr, "Unknown sRGB intent");
906 return;
907 }
908
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600909#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600910 if ((info_ptr->valid & PNG_INFO_gAMA))
911 {
912 int igamma;
913#ifdef PNG_FIXED_POINT_SUPPORTED
914 igamma=(int)info_ptr->int_gamma;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600915#else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600916# ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500917 igamma=(int)(info_ptr->gamma * 100000.);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600918# endif
919#endif
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500920#if 0 && defined(PNG_cHRM_SUPPORTED) && !defined(PNG_FIXED_POINT_SUPPORTED)
921/* We need to define these here because they aren't in png.h */
922 png_fixed_point int_x_white;
923 png_fixed_point int_y_white;
924 png_fixed_point int_x_red;
925 png_fixed_point int_y_red;
926 png_fixed_point int_x_green;
927 png_fixed_point int_y_green;
928 png_fixed_point int_x_blue;
929 png_fixed_point int_y_blue;
930#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600931 if(igamma < 45000L || igamma > 46000L)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600932 {
933 png_warning(png_ptr,
934 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500935#ifndef PNG_NO_CONSOLE_IO
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600936# ifdef PNG_FIXED_POINT_SUPPORTED
937 fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
938# else
939# ifdef PNG_FLOATING_POINT_SUPPORTED
940 fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
941# endif
942# endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600943#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600944 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600945 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600946#endif /* PNG_READ_gAMA_SUPPORTED */
947
948#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500949#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600950 if (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600951 if (abs(info_ptr->int_x_white - 31270L) > 1000 ||
952 abs(info_ptr->int_y_white - 32900L) > 1000 ||
953 abs( info_ptr->int_x_red - 64000L) > 1000 ||
954 abs( info_ptr->int_y_red - 33000L) > 1000 ||
955 abs(info_ptr->int_x_green - 30000L) > 1000 ||
956 abs(info_ptr->int_y_green - 60000L) > 1000 ||
957 abs( info_ptr->int_x_blue - 15000L) > 1000 ||
958 abs( info_ptr->int_y_blue - 6000L) > 1000)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600959 {
960 png_warning(png_ptr,
961 "Ignoring incorrect cHRM value when sRGB is also present");
962 }
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -0500963#endif /* PNG_FIXED_POINT_SUPPORTED */
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600964#endif /* PNG_READ_cHRM_SUPPORTED */
965
966 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
967}
968#endif /* PNG_READ_sRGB_SUPPORTED */
969
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600970#if defined(PNG_READ_iCCP_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500971void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600972png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
973/* Note: this does not properly handle chunks that are > 64K under DOS */
974{
975 png_charp chunkdata;
976 png_byte compression_type;
977 png_charp profile;
978 png_uint_32 skip = 0;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -0600979 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600980
981 png_debug(1, "in png_handle_iCCP\n");
982
983 if (!(png_ptr->mode & PNG_HAVE_IHDR))
984 png_error(png_ptr, "Missing IHDR before iCCP");
985 else if (png_ptr->mode & PNG_HAVE_IDAT)
986 {
987 png_warning(png_ptr, "Invalid iCCP after IDAT");
988 png_crc_finish(png_ptr, length);
989 return;
990 }
991 else if (png_ptr->mode & PNG_HAVE_PLTE)
992 /* Should be an error, but we can cope with it */
993 png_warning(png_ptr, "Out of place iCCP chunk");
994
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600995 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600996 {
997 png_warning(png_ptr, "Duplicate iCCP chunk");
998 png_crc_finish(png_ptr, length);
999 return;
1000 }
1001
1002#ifdef PNG_MAX_MALLOC_64K
1003 if (length > (png_uint_32)65535L)
1004 {
1005 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1006 skip = length - (png_uint_32)65535L;
1007 length = (png_uint_32)65535L;
1008 }
1009#endif
1010
1011 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
1012 slength = (png_size_t)length;
1013 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
1014
1015 if (png_crc_finish(png_ptr, skip))
1016 {
1017 png_free(png_ptr, chunkdata);
1018 return;
1019 }
1020
1021 chunkdata[slength] = 0x00;
1022
1023 for (profile = chunkdata; *profile; profile++)
1024 /* empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001025
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001026 ++profile;
1027
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001028 /* there should be at least one zero (the compression type byte)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001029 following the separator, and we should be on it */
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001030 if (*profile || profile >= chunkdata + slength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001031 {
1032 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001033 png_warning(png_ptr, "malformed iCCP chunk");
1034 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001035 }
1036
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001037 /* compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001038 compression_type = *profile++;
1039
1040 prefix_length = profile - chunkdata;
1041 chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001042 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001043
1044 png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001045 chunkdata + prefix_length, data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001046 png_free(png_ptr, chunkdata);
1047}
1048#endif /* PNG_READ_iCCP_SUPPORTED */
1049
1050#if defined(PNG_READ_sPLT_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001051void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001052png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1053/* Note: this does not properly handle chunks that are > 64K under DOS */
1054{
1055 png_bytep chunkdata;
1056 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001057 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001058#ifdef PNG_NO_POINTER_INDEXING
1059 png_sPLT_entryp pp;
1060#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001061 int data_length, entry_size, i;
1062 png_uint_32 skip = 0;
1063 png_size_t slength;
1064
1065 png_debug(1, "in png_handle_sPLT\n");
1066
1067 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1068 png_error(png_ptr, "Missing IHDR before sPLT");
1069 else if (png_ptr->mode & PNG_HAVE_IDAT)
1070 {
1071 png_warning(png_ptr, "Invalid sPLT after IDAT");
1072 png_crc_finish(png_ptr, length);
1073 return;
1074 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001075
1076#ifdef PNG_MAX_MALLOC_64K
1077 if (length > (png_uint_32)65535L)
1078 {
1079 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1080 skip = length - (png_uint_32)65535L;
1081 length = (png_uint_32)65535L;
1082 }
1083#endif
1084
1085 chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
1086 slength = (png_size_t)length;
1087 png_crc_read(png_ptr, chunkdata, slength);
1088
1089 if (png_crc_finish(png_ptr, skip))
1090 {
1091 png_free(png_ptr, chunkdata);
1092 return;
1093 }
1094
1095 chunkdata[slength] = 0x00;
1096
1097 for (entry_start = chunkdata; *entry_start; entry_start++)
1098 /* empty loop to find end of name */ ;
1099 ++entry_start;
1100
1101 /* a sample depth should follow the separator, and we should be on it */
1102 if (entry_start > chunkdata + slength)
1103 {
1104 png_free(png_ptr, chunkdata);
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001105 png_warning(png_ptr, "malformed sPLT chunk");
1106 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001107 }
1108
1109 new_palette.depth = *entry_start++;
1110 entry_size = (new_palette.depth == 8 ? 6 : 10);
1111 data_length = (slength - (entry_start - chunkdata));
1112
1113 /* integrity-check the data length */
1114 if (data_length % entry_size)
1115 {
1116 png_free(png_ptr, chunkdata);
1117 png_error(png_ptr, "sPLT chunk has bad length");
1118 }
1119
1120 new_palette.nentries = data_length / entry_size;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001121 new_palette.entries = (png_sPLT_entryp)png_malloc(
1122 png_ptr, new_palette.nentries * sizeof(png_sPLT_entry));
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001123
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001124#ifndef PNG_NO_POINTER_INDEXING
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001125 for (i = 0; i < new_palette.nentries; i++)
1126 {
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001127 png_sPLT_entryp pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001128
1129 if (new_palette.depth == 8)
1130 {
1131 pp->red = *entry_start++;
1132 pp->green = *entry_start++;
1133 pp->blue = *entry_start++;
1134 pp->alpha = *entry_start++;
1135 }
1136 else
1137 {
1138 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1139 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1140 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1141 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1142 }
1143 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1144 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001145#else
1146 pp = new_palette.entries;
1147 for (i = 0; i < new_palette.nentries; i++)
1148 {
1149
1150 if (new_palette.depth == 8)
1151 {
1152 pp[i].red = *entry_start++;
1153 pp[i].green = *entry_start++;
1154 pp[i].blue = *entry_start++;
1155 pp[i].alpha = *entry_start++;
1156 }
1157 else
1158 {
1159 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1160 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1161 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1162 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1163 }
1164 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1165 }
1166#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001167
1168 /* discard all chunk data except the name and stash that */
1169 new_palette.name = (png_charp)chunkdata;
1170
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001171 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001172
1173 png_free(png_ptr, chunkdata);
1174 png_free(png_ptr, new_palette.entries);
1175}
1176#endif /* PNG_READ_sPLT_SUPPORTED */
1177
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001178#if defined(PNG_READ_tRNS_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001179void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001180png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001181{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001182 png_debug(1, "in png_handle_tRNS\n");
1183
Guy Schalnate5a37791996-06-05 15:50:50 -05001184 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1185 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001186 else if (png_ptr->mode & PNG_HAVE_IDAT)
1187 {
1188 png_warning(png_ptr, "Invalid tRNS after IDAT");
1189 png_crc_finish(png_ptr, length);
1190 return;
1191 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001192 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001193 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001194 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001195 png_crc_finish(png_ptr, length);
1196 return;
1197 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001198
Guy Schalnat0d580581995-07-20 02:43:20 -05001199 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1200 {
Guy Schalnate5a37791996-06-05 15:50:50 -05001201 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1202 {
1203 /* Should be an error, but we can cope with it */
1204 png_warning(png_ptr, "Missing PLTE before tRNS");
1205 }
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001206 else if (length > (png_uint_32)png_ptr->num_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -05001207 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001208 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001209 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001210 return;
1211 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001212 if (length == 0)
1213 {
1214 png_warning(png_ptr, "Zero length tRNS chunk");
1215 png_crc_finish(png_ptr, length);
1216 return;
1217 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001218
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001219 png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001220 png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001221 png_ptr->num_trans = (png_uint_16)length;
Guy Schalnat0d580581995-07-20 02:43:20 -05001222 }
1223 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1224 {
1225 png_byte buf[6];
1226
1227 if (length != 6)
1228 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001229 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001230 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001231 return;
1232 }
1233
Andreas Dilger47a0c421997-05-16 02:46:07 -05001234 png_crc_read(png_ptr, buf, (png_size_t)length);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001235 png_ptr->num_trans = 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05001236 png_ptr->trans_values.red = png_get_uint_16(buf);
1237 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1238 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1239 }
1240 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
1241 {
1242 png_byte buf[6];
1243
1244 if (length != 2)
1245 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001246 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001247 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001248 return;
1249 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001250
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001251 png_crc_read(png_ptr, buf, 2);
1252 png_ptr->num_trans = 1;
1253 png_ptr->trans_values.gray = png_get_uint_16(buf);
1254 }
1255 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001256 {
1257 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001258 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001259 return;
1260 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001261
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001262 if (png_crc_finish(png_ptr, 0))
1263 return;
1264
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001265#ifdef PNG_FREE_ME_SUPPORTED
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -05001266 png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001267 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1268 png_ptr->free_me |= PNG_FREE_TRNS;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001269#else
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001270 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1271 png_ptr->flags |= PNG_FLAG_FREE_TRNS;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001272#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001273 png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -05001274 &(png_ptr->trans_values));
1275}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001276#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001277
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001278#if defined(PNG_READ_bKGD_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001279void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001280png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001281{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001282 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001283 png_byte buf[6];
1284
Andreas Dilger47a0c421997-05-16 02:46:07 -05001285 png_debug(1, "in png_handle_bKGD\n");
1286
Guy Schalnate5a37791996-06-05 15:50:50 -05001287 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1288 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001289 else if (png_ptr->mode & PNG_HAVE_IDAT)
1290 {
1291 png_warning(png_ptr, "Invalid bKGD after IDAT");
1292 png_crc_finish(png_ptr, length);
1293 return;
1294 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001295 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1296 !(png_ptr->mode & PNG_HAVE_PLTE))
1297 {
1298 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001299 png_crc_finish(png_ptr, length);
1300 return;
1301 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001302 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001303 {
1304 png_warning(png_ptr, "Duplicate bKGD chunk");
1305 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001306 return;
1307 }
1308
Guy Schalnat0d580581995-07-20 02:43:20 -05001309 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1310 truelen = 1;
1311 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1312 truelen = 6;
1313 else
1314 truelen = 2;
1315
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001316 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001317 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001318 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001319 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001320 return;
1321 }
1322
Andreas Dilger47a0c421997-05-16 02:46:07 -05001323 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001324 if (png_crc_finish(png_ptr, 0))
1325 return;
1326
Guy Schalnate5a37791996-06-05 15:50:50 -05001327 /* We convert the index value into RGB components so that we can allow
1328 * arbitrary RGB values for background when we have transparency, and
1329 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001330 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001331 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001332 {
Guy Schalnat0d580581995-07-20 02:43:20 -05001333 png_ptr->background.index = buf[0];
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001334 if(info_ptr->num_palette)
1335 {
1336 if(buf[0] > info_ptr->num_palette)
1337 {
1338 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1339 png_crc_finish(png_ptr, length);
1340 return;
1341 }
1342 png_ptr->background.red =
1343 (png_uint_16)png_ptr->palette[buf[0]].red;
1344 png_ptr->background.green =
1345 (png_uint_16)png_ptr->palette[buf[0]].green;
1346 png_ptr->background.blue =
1347 (png_uint_16)png_ptr->palette[buf[0]].blue;
1348 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001349 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001350 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001351 {
1352 png_ptr->background.red =
1353 png_ptr->background.green =
1354 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -05001355 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001356 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001357 else
1358 {
1359 png_ptr->background.red = png_get_uint_16(buf);
1360 png_ptr->background.green = png_get_uint_16(buf + 2);
1361 png_ptr->background.blue = png_get_uint_16(buf + 4);
1362 }
1363
Andreas Dilger47a0c421997-05-16 02:46:07 -05001364 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -05001365}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001366#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001367
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001368#if defined(PNG_READ_hIST_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001369void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001370png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001371{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001372 int num, i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001373
Andreas Dilger47a0c421997-05-16 02:46:07 -05001374 png_debug(1, "in png_handle_hIST\n");
1375
Guy Schalnate5a37791996-06-05 15:50:50 -05001376 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1377 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001378 else if (png_ptr->mode & PNG_HAVE_IDAT)
1379 {
1380 png_warning(png_ptr, "Invalid hIST after IDAT");
1381 png_crc_finish(png_ptr, length);
1382 return;
1383 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001384 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1385 {
1386 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001387 png_crc_finish(png_ptr, length);
1388 return;
1389 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001390 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001391 {
1392 png_warning(png_ptr, "Duplicate hIST chunk");
1393 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001394 return;
1395 }
1396
Andreas Dilger47a0c421997-05-16 02:46:07 -05001397 if (length != (png_uint_32)(2 * png_ptr->num_palette))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001398 {
1399 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001400 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001401 return;
1402 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001403
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05001404 num = (int)length / 2 ;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001405 png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001406 (png_uint_32)(num * sizeof (png_uint_16)));
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001407 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001408 {
1409 png_byte buf[2];
1410
1411 png_crc_read(png_ptr, buf, 2);
1412 png_ptr->hist[i] = png_get_uint_16(buf);
1413 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001414
1415 if (png_crc_finish(png_ptr, 0))
1416 return;
1417
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001418#ifdef PNG_FREE_ME_SUPPORTED
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -05001419 png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
1420 png_ptr->free_me |= PNG_FREE_HIST;
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05001421#else
1422 png_ptr->flags |= PNG_FLAG_FREE_HIST;
1423#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001424 png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
Guy Schalnat0d580581995-07-20 02:43:20 -05001425}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001426#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001427
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001428#if defined(PNG_READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001429void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001430png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001431{
1432 png_byte buf[9];
1433 png_uint_32 res_x, res_y;
1434 int unit_type;
1435
Andreas Dilger47a0c421997-05-16 02:46:07 -05001436 png_debug(1, "in png_handle_pHYs\n");
1437
Guy Schalnate5a37791996-06-05 15:50:50 -05001438 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001439 png_error(png_ptr, "Missing IHDR before pHYs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001440 else if (png_ptr->mode & PNG_HAVE_IDAT)
1441 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001442 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001443 png_crc_finish(png_ptr, length);
1444 return;
1445 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001446 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001447 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001448 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001449 png_crc_finish(png_ptr, length);
1450 return;
1451 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001452
Guy Schalnat0d580581995-07-20 02:43:20 -05001453 if (length != 9)
1454 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001455 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001456 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001457 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001458 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001459
1460 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001461 if (png_crc_finish(png_ptr, 0))
1462 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001463
1464 res_x = png_get_uint_32(buf);
1465 res_y = png_get_uint_32(buf + 4);
1466 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001467 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001468}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001469#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001470
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001471#if defined(PNG_READ_oFFs_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001472void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001473png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001474{
1475 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001476 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001477 int unit_type;
1478
Andreas Dilger47a0c421997-05-16 02:46:07 -05001479 png_debug(1, "in png_handle_oFFs\n");
1480
Guy Schalnate5a37791996-06-05 15:50:50 -05001481 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1482 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001483 else if (png_ptr->mode & PNG_HAVE_IDAT)
1484 {
1485 png_warning(png_ptr, "Invalid oFFs after IDAT");
1486 png_crc_finish(png_ptr, length);
1487 return;
1488 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001489 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001490 {
1491 png_warning(png_ptr, "Duplicate oFFs chunk");
1492 png_crc_finish(png_ptr, length);
1493 return;
1494 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001495
Guy Schalnat0d580581995-07-20 02:43:20 -05001496 if (length != 9)
1497 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001498 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001499 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001500 return;
1501 }
1502
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001503 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001504 if (png_crc_finish(png_ptr, 0))
1505 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001506
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001507 offset_x = png_get_int_32(buf);
1508 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001509 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001510 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1511}
1512#endif
1513
1514#if defined(PNG_READ_pCAL_SUPPORTED)
Glenn Randers-Pehrsonff9c9472000-07-11 07:12:36 -05001515/* read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001516void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001517png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1518{
1519 png_charp purpose;
1520 png_int_32 X0, X1;
1521 png_byte type, nparams;
1522 png_charp buf, units, endptr;
1523 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001524 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001525 int i;
1526
1527 png_debug(1, "in png_handle_pCAL\n");
1528
1529 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1530 png_error(png_ptr, "Missing IHDR before pCAL");
1531 else if (png_ptr->mode & PNG_HAVE_IDAT)
1532 {
1533 png_warning(png_ptr, "Invalid pCAL after IDAT");
1534 png_crc_finish(png_ptr, length);
1535 return;
1536 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001537 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001538 {
1539 png_warning(png_ptr, "Duplicate pCAL chunk");
1540 png_crc_finish(png_ptr, length);
1541 return;
1542 }
1543
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001544 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
Andreas Dilger47a0c421997-05-16 02:46:07 -05001545 length + 1);
1546 purpose = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001547 slength = (png_size_t)length;
1548 png_crc_read(png_ptr, (png_bytep)purpose, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001549
1550 if (png_crc_finish(png_ptr, 0))
1551 {
1552 png_free(png_ptr, purpose);
1553 return;
1554 }
1555
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001556 purpose[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001557
1558 png_debug(3, "Finding end of pCAL purpose string\n");
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001559 for (buf = purpose; *buf; buf++)
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001560 /* empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001561
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001562 endptr = purpose + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001563
1564 /* We need to have at least 12 bytes after the purpose string
1565 in order to get the parameter information. */
1566 if (endptr <= buf + 12)
1567 {
1568 png_warning(png_ptr, "Invalid pCAL data");
1569 png_free(png_ptr, purpose);
1570 return;
1571 }
1572
1573 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1574 X0 = png_get_int_32((png_bytep)buf+1);
1575 X1 = png_get_int_32((png_bytep)buf+5);
1576 type = buf[9];
1577 nparams = buf[10];
1578 units = buf + 11;
1579
1580 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1581 /* Check that we have the right number of parameters for known
1582 equation types. */
1583 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1584 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1585 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1586 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1587 {
1588 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
1589 png_free(png_ptr, purpose);
1590 return;
1591 }
1592 else if (type >= PNG_EQUATION_LAST)
1593 {
1594 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1595 }
1596
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001597 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001598 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001599
1600 png_debug(3, "Allocating pCAL parameters array\n");
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001601 params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams
1602 *sizeof(png_charp))) ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001603
1604 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001605 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001606 {
1607 buf++; /* Skip the null string terminator from previous parameter. */
1608
1609 png_debug1(3, "Reading pCAL parameter %d\n", i);
Glenn Randers-Pehrsond12aa501998-03-13 07:39:39 -06001610 for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001611 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001612
1613 /* Make sure we haven't run out of data yet */
1614 if (buf > endptr)
1615 {
1616 png_warning(png_ptr, "Invalid pCAL data");
1617 png_free(png_ptr, purpose);
1618 png_free(png_ptr, params);
1619 return;
1620 }
1621 }
1622
1623 png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
1624 units, params);
1625
1626 png_free(png_ptr, purpose);
1627 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001628}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001629#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001630
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001631#if defined(PNG_READ_sCAL_SUPPORTED)
1632/* read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001633void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001634png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1635{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001636 png_charp buffer, ep;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001637#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001638 double width, height;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001639 png_charp vp;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001640#else
1641#ifdef PNG_FIXED_POINT_SUPPORTED
1642 png_charp swidth, sheight;
1643#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001644#endif
1645 png_size_t slength;
1646
1647 png_debug(1, "in png_handle_sCAL\n");
1648
1649 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1650 png_error(png_ptr, "Missing IHDR before sCAL");
1651 else if (png_ptr->mode & PNG_HAVE_IDAT)
1652 {
1653 png_warning(png_ptr, "Invalid sCAL after IDAT");
1654 png_crc_finish(png_ptr, length);
1655 return;
1656 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001657 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001658 {
1659 png_warning(png_ptr, "Duplicate sCAL chunk");
1660 png_crc_finish(png_ptr, length);
1661 return;
1662 }
1663
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05001664 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001665 length + 1);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001666 buffer = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001667 slength = (png_size_t)length;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001668 png_crc_read(png_ptr, (png_bytep)buffer, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001669
1670 if (png_crc_finish(png_ptr, 0))
1671 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001672 png_free(png_ptr, buffer);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001673 return;
1674 }
1675
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001676 buffer[slength] = 0x00; /* null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001677
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001678 ep = buffer + 1; /* skip unit byte */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001679
1680#ifdef PNG_FLOATING_POINT_SUPPORTED
1681 width = strtod(ep, &vp);
1682 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001683 {
1684 png_warning(png_ptr, "malformed width string in sCAL chunk");
1685 return;
1686 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001687#else
1688#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001689 swidth = (png_charp)png_malloc(png_ptr, strlen(ep) + 1);
1690 png_memcpy(swidth, ep, (png_size_t)strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001691#endif
1692#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001693
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001694 for (ep = buffer; *ep; ep++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001695 /* empty loop */ ;
1696 ep++;
1697
1698#ifdef PNG_FLOATING_POINT_SUPPORTED
1699 height = strtod(ep, &vp);
1700 if (*vp)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001701 {
1702 png_warning(png_ptr, "malformed height string in sCAL chunk");
1703 return;
1704 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001705#else
1706#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001707 sheight = (png_charp)png_malloc(png_ptr, strlen(ep) + 1);
1708 png_memcpy(sheight, ep, (png_size_t)strlen(ep));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001709#endif
1710#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001711
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001712 if (buffer + slength < ep
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001713#ifdef PNG_FLOATING_POINT_SUPPORTED
1714 || width <= 0. || height <= 0.
1715#endif
1716 )
1717 {
1718 png_warning(png_ptr, "Invalid sCAL data");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001719 png_free(png_ptr, buffer);
1720#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001721 png_free(png_ptr, swidth);
1722 png_free(png_ptr, sheight);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001723#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001724 return;
1725 }
1726
1727
1728#ifdef PNG_FLOATING_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001729 png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
1730#else
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001731#ifdef PNG_FIXED_POINT_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001732 png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
1733#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001734#endif
1735
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001736 png_free(png_ptr, buffer);
1737#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1738 png_free(png_ptr, swidth);
1739 png_free(png_ptr, sheight);
1740#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001741}
1742#endif
1743
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001744#if defined(PNG_READ_tIME_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001745void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001746png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001747{
1748 png_byte buf[7];
1749 png_time mod_time;
1750
Andreas Dilger47a0c421997-05-16 02:46:07 -05001751 png_debug(1, "in png_handle_tIME\n");
1752
Guy Schalnate5a37791996-06-05 15:50:50 -05001753 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001754 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001755 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001756 {
1757 png_warning(png_ptr, "Duplicate tIME chunk");
1758 png_crc_finish(png_ptr, length);
1759 return;
1760 }
1761
1762 if (png_ptr->mode & PNG_HAVE_IDAT)
1763 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001764
Guy Schalnat0d580581995-07-20 02:43:20 -05001765 if (length != 7)
1766 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001767 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001768 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001769 return;
1770 }
1771
1772 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001773 if (png_crc_finish(png_ptr, 0))
1774 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001775
1776 mod_time.second = buf[6];
1777 mod_time.minute = buf[5];
1778 mod_time.hour = buf[4];
1779 mod_time.day = buf[3];
1780 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001781 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001782
Andreas Dilger47a0c421997-05-16 02:46:07 -05001783 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001784}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001785#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001786
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001787#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001788/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001789void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001790png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001791{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001792 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001793 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001794 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001795 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001796 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001797
1798 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001799
Guy Schalnate5a37791996-06-05 15:50:50 -05001800 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1801 png_error(png_ptr, "Missing IHDR before tEXt");
1802
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001803 if (png_ptr->mode & PNG_HAVE_IDAT)
1804 png_ptr->mode |= PNG_AFTER_IDAT;
1805
Andreas Dilger47a0c421997-05-16 02:46:07 -05001806#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001807 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001808 {
1809 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001810 skip = length - (png_uint_32)65535L;
1811 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001812 }
1813#endif
1814
1815 key = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001816 slength = (png_size_t)length;
1817 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001818
1819 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001820 {
1821 png_free(png_ptr, key);
1822 return;
1823 }
1824
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001825 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001826
1827 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001828 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001829
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001830 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001831 text++;
1832
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001833 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001834 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1835 text_ptr->key = key;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001836#ifdef PNG_iTXt_SUPPORTED
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001837 text_ptr->lang = NULL;
1838 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001839 text_ptr->itxt_length = 0;
1840#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001841 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001842 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001843
1844 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1845
Glenn Randers-Pehrson6d8f3b01999-10-23 08:39:18 -05001846 png_free(png_ptr, key);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001847 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001848}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001849#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001850
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001851#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001852/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001853void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001854png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001855{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001856 png_textp text_ptr;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001857 png_charp chunkdata;
Guy Schalnat6d764711995-12-19 03:22:19 -06001858 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001859 int comp_type;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001860 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001861
1862 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnate5a37791996-06-05 15:50:50 -05001863 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1864 png_error(png_ptr, "Missing IHDR before zTXt");
1865
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001866 if (png_ptr->mode & PNG_HAVE_IDAT)
1867 png_ptr->mode |= PNG_AFTER_IDAT;
1868
Andreas Dilger47a0c421997-05-16 02:46:07 -05001869#ifdef PNG_MAX_MALLOC_64K
1870 /* We will no doubt have problems with chunks even half this size, but
1871 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001872 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001873 {
1874 png_warning(png_ptr,"zTXt chunk too large to fit in memory");
1875 png_crc_finish(png_ptr, length);
1876 return;
1877 }
1878#endif
1879
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001880 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001881 slength = (png_size_t)length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001882 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001883 if (png_crc_finish(png_ptr, 0))
1884 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001885 png_free(png_ptr, chunkdata);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001886 return;
1887 }
1888
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001889 chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001890
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001891 for (text = chunkdata; *text; text++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001892 /* empty loop */ ;
1893
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001894 /* zTXt must have some text after the chunkdataword */
1895 if (text == chunkdata + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001896 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001897 comp_type = PNG_TEXT_COMPRESSION_NONE;
Guy Schalnat69b14481996-01-10 02:56:49 -06001898 png_warning(png_ptr, "Zero length zTXt chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001899 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001900 else
Guy Schalnat0d580581995-07-20 02:43:20 -05001901 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001902 comp_type = *(++text);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001903 text++; /* skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05001904 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001905 prefix_len = text - chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05001906
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001907 chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001908 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001909
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001910 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001911 text_ptr->compression = comp_type;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001912 text_ptr->key = chunkdata;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001913#ifdef PNG_iTXt_SUPPORTED
1914 text_ptr->lang = NULL;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001915 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001916 text_ptr->itxt_length = 0;
1917#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001918 text_ptr->text = chunkdata + prefix_len;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001919 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001920
1921 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1922
1923 png_free(png_ptr, text_ptr);
1924 png_free(png_ptr, chunkdata);
1925}
1926#endif
1927
1928#if defined(PNG_READ_iTXt_SUPPORTED)
1929/* note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001930void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001931png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1932{
1933 png_textp text_ptr;
1934 png_charp chunkdata;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001935 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001936 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001937 int comp_type = 0;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001938 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001939
1940 png_debug(1, "in png_handle_iTXt\n");
1941
1942 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1943 png_error(png_ptr, "Missing IHDR before iTXt");
1944
1945 if (png_ptr->mode & PNG_HAVE_IDAT)
1946 png_ptr->mode |= PNG_AFTER_IDAT;
1947
1948#ifdef PNG_MAX_MALLOC_64K
1949 /* We will no doubt have problems with chunks even half this size, but
1950 there is no hard and fast rule to tell us where to stop. */
1951 if (length > (png_uint_32)65535L)
1952 {
1953 png_warning(png_ptr,"iTXt chunk too large to fit in memory");
1954 png_crc_finish(png_ptr, length);
1955 return;
1956 }
1957#endif
1958
1959 chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
1960 slength = (png_size_t)length;
1961 png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
1962 if (png_crc_finish(png_ptr, 0))
1963 {
1964 png_free(png_ptr, chunkdata);
1965 return;
1966 }
1967
1968 chunkdata[slength] = 0x00;
1969
1970 for (lang = chunkdata; *lang; lang++)
1971 /* empty loop */ ;
1972 lang++; /* skip NUL separator */
1973
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001974 /* iTXt must have a language tag (possibly empty), two compression bytes,
1975 translated keyword (possibly empty), and possibly some text after the
1976 keyword */
1977
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001978 if (lang >= chunkdata + slength)
1979 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001980 comp_flag = PNG_TEXT_COMPRESSION_NONE;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001981 png_warning(png_ptr, "Zero length iTXt chunk");
1982 }
1983 else
1984 {
1985 comp_flag = *lang++;
1986 comp_type = *lang++;
1987 }
1988
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001989 for (lang_key = lang; *lang_key; lang_key++)
1990 /* empty loop */ ;
1991 lang_key++; /* skip NUL separator */
1992
1993 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001994 /* empty loop */ ;
1995 text++; /* skip NUL separator */
1996
1997 prefix_len = text - chunkdata;
1998
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001999 key=chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002000 if (comp_flag)
2001 chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002002 (size_t)length, prefix_len, &data_len);
2003 else
2004 data_len=png_strlen(chunkdata + prefix_len);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002005 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002006 text_ptr->compression = (int)comp_flag + 1;
2007 text_ptr->lang_key = chunkdata+(lang_key-key);
2008 text_ptr->lang = chunkdata+(lang-key);
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002009 text_ptr->itxt_length = data_len;
2010 text_ptr->text_length = 0;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002011 text_ptr->key = chunkdata;
2012 text_ptr->text = chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002013
2014 png_set_text(png_ptr, info_ptr, text_ptr, 1);
2015
2016 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002017 png_free(png_ptr, chunkdata);
2018}
2019#endif
2020
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002021/* This function is called when we haven't found a handler for a
2022 chunk. If there isn't a problem with the chunk itself (ie bad
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002023 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2024 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2025 case it will be saved away to be written out later. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002026void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002027png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2028{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002029 png_uint_32 skip = 0;
2030
Andreas Dilger47a0c421997-05-16 02:46:07 -05002031 png_debug(1, "in png_handle_unknown\n");
2032
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002033 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002034 {
2035#ifdef PNG_USE_LOCAL_ARRAYS
2036 PNG_IDAT;
2037#endif
2038 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
2039 png_ptr->mode |= PNG_AFTER_IDAT;
2040 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002041
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002042 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
2043
2044 if (!(png_ptr->chunk_name[0] & 0x20))
2045 {
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002046#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002047 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2048 HANDLE_CHUNK_ALWAYS
2049#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
2050 && png_ptr->read_user_chunk_fn == (png_user_chunk_ptr)NULL
2051#endif
2052 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002053#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002054 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002055 }
2056
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002057#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
2058 if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
2059 {
2060 png_unknown_chunk chunk;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002061
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002062#ifdef PNG_MAX_MALLOC_64K
2063 if (length > (png_uint_32)65535L)
2064 {
2065 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2066 skip = length - (png_uint_32)65535L;
2067 length = (png_uint_32)65535L;
2068 }
2069#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002070 strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002071 chunk.data = (png_bytep)png_malloc(png_ptr, length);
2072 png_crc_read(png_ptr, chunk.data, length);
2073 chunk.size = length;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002074#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
2075 if(png_ptr->read_user_chunk_fn != (png_user_chunk_ptr)NULL)
2076 {
2077 /* callback to user unknown chunk handler */
2078 if ((*(png_ptr->read_user_chunk_fn)) (png_ptr, &chunk) <= 0)
2079 {
2080 if (!(png_ptr->chunk_name[0] & 0x20))
2081 if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2082 HANDLE_CHUNK_ALWAYS)
2083 png_chunk_error(png_ptr, "unknown critical chunk");
2084 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
2085 }
2086 }
2087 else
2088#endif
2089 png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002090 png_free(png_ptr, chunk.data);
2091 }
2092 else
2093#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002094 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002095
2096 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002097
2098#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
2099 if (info_ptr == NULL)
2100 /* quiet compiler warnings about unused info_ptr */ ;
2101#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002102}
2103
2104/* This function is called to verify that a chunk name is valid.
2105 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05002106 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002107 functions to handle unknown critical chunks after we check that
2108 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002109
2110#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
2111
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002112void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002113png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2114{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002115 png_debug(1, "in png_check_chunk_name\n");
2116 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
2117 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002118 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002119 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002120 }
2121}
2122
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002123/* Combines the row recently read in with the existing pixels in the
2124 row. This routine takes care of alpha and transparency if requested.
Guy Schalnat0d580581995-07-20 02:43:20 -05002125 This routine also handles the two methods of progressive display
2126 of interlaced images, depending on the mask value.
2127 The mask value describes which pixels are to be combined with
2128 the row. The pattern always repeats every 8 pixels, so just 8
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002129 bits are needed. A one indicates the pixel is to be combined,
Guy Schalnat0d580581995-07-20 02:43:20 -05002130 a zero indicates the pixel is to be skipped. This is in addition
2131 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002132 you want all pixels to be combined, pass 0xff (255) in mask. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002133void /* PRIVATE */
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002134#ifdef PNG_HAVE_ASSEMBLER_COMBINE_ROW
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -05002135png_combine_row_c
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002136#else
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -05002137png_combine_row
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002138#endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */
2139 (png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002140{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002141 png_debug(1,"in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002142 if (mask == 0xff)
2143 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002144 png_memcpy(row, png_ptr->row_buf + 1,
Guy Schalnat0d580581995-07-20 02:43:20 -05002145 (png_size_t)((png_ptr->width *
2146 png_ptr->row_info.pixel_depth + 7) >> 3));
2147 }
2148 else
2149 {
2150 switch (png_ptr->row_info.pixel_depth)
2151 {
2152 case 1:
2153 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002154 png_bytep sp = png_ptr->row_buf + 1;
2155 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002156 int s_inc, s_start, s_end;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002157 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002158 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002159 png_uint_32 i;
2160 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002161
Andreas Dilger47a0c421997-05-16 02:46:07 -05002162#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2163 if (png_ptr->transformations & PNG_PACKSWAP)
2164 {
2165 s_start = 0;
2166 s_end = 7;
2167 s_inc = 1;
2168 }
2169 else
2170#endif
2171 {
2172 s_start = 7;
2173 s_end = 0;
2174 s_inc = -1;
2175 }
2176
2177 shift = s_start;
2178
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002179 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002180 {
2181 if (m & mask)
2182 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002183 int value;
2184
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002185 value = (*sp >> shift) & 0x01;
Guy Schalnat0d580581995-07-20 02:43:20 -05002186 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002187 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002188 }
2189
Andreas Dilger47a0c421997-05-16 02:46:07 -05002190 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002191 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002192 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002193 sp++;
2194 dp++;
2195 }
2196 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002197 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002198
2199 if (m == 1)
2200 m = 0x80;
2201 else
2202 m >>= 1;
2203 }
2204 break;
2205 }
2206 case 2:
2207 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002208 png_bytep sp = png_ptr->row_buf + 1;
2209 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002210 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002211 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002212 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002213 png_uint_32 i;
2214 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002215 int value;
2216
Andreas Dilger47a0c421997-05-16 02:46:07 -05002217#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2218 if (png_ptr->transformations & PNG_PACKSWAP)
2219 {
2220 s_start = 0;
2221 s_end = 6;
2222 s_inc = 2;
2223 }
2224 else
2225#endif
2226 {
2227 s_start = 6;
2228 s_end = 0;
2229 s_inc = -2;
2230 }
2231
2232 shift = s_start;
2233
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002234 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002235 {
2236 if (m & mask)
2237 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002238 value = (*sp >> shift) & 0x03;
Guy Schalnat0d580581995-07-20 02:43:20 -05002239 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002240 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002241 }
2242
Andreas Dilger47a0c421997-05-16 02:46:07 -05002243 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002244 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002245 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002246 sp++;
2247 dp++;
2248 }
2249 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002250 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002251 if (m == 1)
2252 m = 0x80;
2253 else
2254 m >>= 1;
2255 }
2256 break;
2257 }
2258 case 4:
2259 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002260 png_bytep sp = png_ptr->row_buf + 1;
2261 png_bytep dp = row;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002262 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002263 int m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002264 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002265 png_uint_32 i;
2266 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002267 int value;
2268
Andreas Dilger47a0c421997-05-16 02:46:07 -05002269#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2270 if (png_ptr->transformations & PNG_PACKSWAP)
2271 {
2272 s_start = 0;
2273 s_end = 4;
2274 s_inc = 4;
2275 }
2276 else
2277#endif
2278 {
2279 s_start = 4;
2280 s_end = 0;
2281 s_inc = -4;
2282 }
2283 shift = s_start;
2284
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002285 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002286 {
2287 if (m & mask)
2288 {
2289 value = (*sp >> shift) & 0xf;
2290 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002291 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05002292 }
2293
Andreas Dilger47a0c421997-05-16 02:46:07 -05002294 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002295 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002296 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002297 sp++;
2298 dp++;
2299 }
2300 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002301 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002302 if (m == 1)
2303 m = 0x80;
2304 else
2305 m >>= 1;
2306 }
2307 break;
2308 }
2309 default:
2310 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002311 png_bytep sp = png_ptr->row_buf + 1;
2312 png_bytep dp = row;
2313 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2314 png_uint_32 i;
2315 png_uint_32 row_width = png_ptr->width;
2316 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002317
Guy Schalnat0d580581995-07-20 02:43:20 -05002318
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002319 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002320 {
2321 if (m & mask)
2322 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002323 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002324 }
2325
2326 sp += pixel_bytes;
2327 dp += pixel_bytes;
2328
2329 if (m == 1)
2330 m = 0x80;
2331 else
2332 m >>= 1;
2333 }
2334 break;
2335 }
2336 }
2337 }
2338}
2339
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002340#if defined(PNG_READ_INTERLACING_SUPPORTED)
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002341void /* PRIVATE */
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002342#ifdef PNG_HAVE_ASSEMBLER_READ_INTERLACE
2343png_do_read_interlace_c
2344#else
2345png_do_read_interlace
2346#endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */
2347 (png_row_infop row_info, png_bytep row, int pass,
Andreas Dilger47a0c421997-05-16 02:46:07 -05002348 png_uint_32 transformations)
Guy Schalnat0d580581995-07-20 02:43:20 -05002349{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002350#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002351 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002352
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002353 /* offset to next interlace block */
2354 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002355#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002356
Andreas Dilger47a0c421997-05-16 02:46:07 -05002357 png_debug(1,"in png_do_read_interlace\n");
2358 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002359 {
2360 png_uint_32 final_width;
2361
2362 final_width = row_info->width * png_pass_inc[pass];
2363
2364 switch (row_info->pixel_depth)
2365 {
2366 case 1:
2367 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002368 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2369 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002370 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002371 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002372 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002373 png_byte v;
2374 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002375 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002376
Andreas Dilger47a0c421997-05-16 02:46:07 -05002377#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2378 if (transformations & PNG_PACKSWAP)
2379 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002380 sshift = (int)((row_info->width + 7) & 0x07);
2381 dshift = (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002382 s_start = 7;
2383 s_end = 0;
2384 s_inc = -1;
2385 }
2386 else
2387#endif
2388 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002389 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2390 dshift = 7 - (int)((final_width + 7) & 0x07);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002391 s_start = 0;
2392 s_end = 7;
2393 s_inc = 1;
2394 }
2395
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002396 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002397 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002398 v = (png_byte)((*sp >> sshift) & 0x01);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002399 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002400 {
2401 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2402 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002403 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002404 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002405 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002406 dp--;
2407 }
2408 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002409 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002410 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002411 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002412 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002413 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002414 sp--;
2415 }
2416 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002417 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002418 }
2419 break;
2420 }
2421 case 2:
2422 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002423 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2424 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002425 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002426 int s_start, s_end, s_inc;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002427 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002428 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002429
Andreas Dilger47a0c421997-05-16 02:46:07 -05002430#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2431 if (transformations & PNG_PACKSWAP)
2432 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002433 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2434 dshift = (int)(((final_width + 3) & 0x03) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002435 s_start = 6;
2436 s_end = 0;
2437 s_inc = -2;
2438 }
2439 else
2440#endif
2441 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002442 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2443 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002444 s_start = 0;
2445 s_end = 6;
2446 s_inc = 2;
2447 }
2448
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002449 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002450 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002451 png_byte v;
2452 int j;
2453
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002454 v = (png_byte)((*sp >> sshift) & 0x03);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002455 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002456 {
2457 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002458 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002459 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002460 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002461 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002462 dp--;
2463 }
2464 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002465 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002466 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002467 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002468 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002469 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002470 sp--;
2471 }
2472 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002473 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002474 }
2475 break;
2476 }
2477 case 4:
2478 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002479 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2480 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06002481 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002482 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002483 png_uint_32 i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002484 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002485
Andreas Dilger47a0c421997-05-16 02:46:07 -05002486#if defined(PNG_READ_PACKSWAP_SUPPORTED)
2487 if (transformations & PNG_PACKSWAP)
2488 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002489 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2490 dshift = (int)(((final_width + 1) & 0x01) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002491 s_start = 4;
2492 s_end = 0;
2493 s_inc = -4;
2494 }
2495 else
2496#endif
2497 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002498 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2499 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002500 s_start = 0;
2501 s_end = 4;
2502 s_inc = 4;
2503 }
2504
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002505 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002506 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002507 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002508 int j;
2509
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002510 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002511 {
2512 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06002513 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002514 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002515 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002516 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002517 dp--;
2518 }
2519 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002520 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002521 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05002522 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05002523 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002524 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002525 sp--;
2526 }
2527 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002528 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002529 }
2530 break;
2531 }
2532 default:
2533 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002534 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
2535 png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
2536 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002537
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002538 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002539 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002540
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002541 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002542 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05002543 png_byte v[8];
2544 int j;
2545
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002546 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002547 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002548 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002549 png_memcpy(dp, v, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002550 dp -= pixel_bytes;
2551 }
2552 sp -= pixel_bytes;
2553 }
2554 break;
2555 }
2556 }
2557 row_info->width = final_width;
2558 row_info->rowbytes = ((final_width *
2559 (png_uint_32)row_info->pixel_depth + 7) >> 3);
2560 }
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05002561#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
2562 /* silence compiler warning */
2563 if (transformations)
2564 return;
2565#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002566}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002567#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002568
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002569void /* PRIVATE */
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05002570#ifdef PNG_HAVE_ASSEMBLER_READ_FILTER_ROW
2571png_read_filter_row_c
2572#else
2573png_read_filter_row
2574#endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */
2575 (png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002576 png_bytep prev_row, int filter)
2577{
2578 png_debug(1, "in png_read_filter_row\n");
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05002579 png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002580 switch (filter)
2581 {
2582 case PNG_FILTER_VALUE_NONE:
2583 break;
2584 case PNG_FILTER_VALUE_SUB:
2585 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002586 png_uint_32 i;
2587 png_uint_32 istop = row_info->rowbytes;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002588 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002589 png_bytep rp = row + bpp;
2590 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002591
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002592 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002593 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002594 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2595 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002596 }
2597 break;
2598 }
2599 case PNG_FILTER_VALUE_UP:
2600 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002601 png_uint_32 i;
2602 png_uint_32 istop = row_info->rowbytes;
2603 png_bytep rp = row;
2604 png_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002605
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002606 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002607 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002608 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2609 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002610 }
2611 break;
2612 }
2613 case PNG_FILTER_VALUE_AVG:
2614 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002615 png_uint_32 i;
2616 png_bytep rp = row;
2617 png_bytep pp = prev_row;
2618 png_bytep lp = row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002619 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002620 png_uint_32 istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002621
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002622 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002623 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002624 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002625 ((int)(*pp++) / 2 )) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002626 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002627 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002628
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002629 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002630 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002631 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002632 (int)(*pp++ + *lp++) / 2 ) & 0xff);
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002633 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002634 }
2635 break;
2636 }
2637 case PNG_FILTER_VALUE_PAETH:
2638 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002639 png_uint_32 i;
2640 png_bytep rp = row;
2641 png_bytep pp = prev_row;
2642 png_bytep lp = row;
2643 png_bytep cp = prev_row;
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002644 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002645 png_uint_32 istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002646
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002647 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002648 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002649 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2650 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002651 }
2652
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002653 for (i = 0; i < istop; i++) /* use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002654 {
2655 int a, b, c, pa, pb, pc, p;
2656
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002657 a = *lp++;
2658 b = *pp++;
2659 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002660
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002661 p = b - c;
2662 pc = a - c;
2663
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002664#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002665 pa = abs(p);
2666 pb = abs(pc);
2667 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002668#else
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002669 pa = p < 0 ? -p : p;
2670 pb = pc < 0 ? -pc : pc;
2671 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002672#endif
2673
2674 /*
2675 if (pa <= pb && pa <= pc)
2676 p = a;
2677 else if (pb <= pc)
2678 p = b;
2679 else
2680 p = c;
2681 */
2682
2683 p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
2684
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05002685 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2686 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002687 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002688 break;
2689 }
2690 default:
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002691 png_warning(png_ptr, "Ignoring bad adaptive filter type");
2692 *row=0;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002693 break;
2694 }
2695}
Guy Schalnat0d580581995-07-20 02:43:20 -05002696
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002697void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002698png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002699{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002700#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002701 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002702
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002703 /* start of interlace block */
2704 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002705
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002706 /* offset to next interlace block */
2707 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002708
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002709 /* start of interlace block in the y direction */
2710 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002711
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002712 /* offset to next interlace block in the y direction */
2713 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002714#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002715
Andreas Dilger47a0c421997-05-16 02:46:07 -05002716 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002717 png_ptr->row_number++;
2718 if (png_ptr->row_number < png_ptr->num_rows)
2719 return;
2720
2721 if (png_ptr->interlaced)
2722 {
2723 png_ptr->row_number = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002724 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002725 do
2726 {
2727 png_ptr->pass++;
2728 if (png_ptr->pass >= 7)
2729 break;
2730 png_ptr->iwidth = (png_ptr->width +
2731 png_pass_inc[png_ptr->pass] - 1 -
2732 png_pass_start[png_ptr->pass]) /
2733 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002734 png_ptr->irowbytes = ((png_ptr->iwidth *
2735 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
2736
Guy Schalnat0d580581995-07-20 02:43:20 -05002737 if (!(png_ptr->transformations & PNG_INTERLACE))
2738 {
2739 png_ptr->num_rows = (png_ptr->height +
2740 png_pass_yinc[png_ptr->pass] - 1 -
2741 png_pass_ystart[png_ptr->pass]) /
2742 png_pass_yinc[png_ptr->pass];
2743 if (!(png_ptr->num_rows))
2744 continue;
2745 }
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002746 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002747 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002748 } while (png_ptr->iwidth == 0);
2749
2750 if (png_ptr->pass < 7)
2751 return;
2752 }
2753
Guy Schalnate5a37791996-06-05 15:50:50 -05002754 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002755 {
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002756#ifdef PNG_USE_LOCAL_ARRAYS
2757 PNG_IDAT;
2758#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002759 char extra;
2760 int ret;
2761
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002762 png_ptr->zstream.next_out = (Byte *)&extra;
2763 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002764 for(;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05002765 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002766 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002767 {
2768 while (!png_ptr->idat_size)
2769 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002770 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002771
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002772 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002773
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002774 png_read_data(png_ptr, chunk_length, 4);
2775 png_ptr->idat_size = png_get_uint_32(chunk_length);
2776
Guy Schalnat0d580581995-07-20 02:43:20 -05002777 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002778 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002779 if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002780 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002781
2782 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002783 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2784 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002785 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002786 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2787 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2788 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002789 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002790 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002791 if (ret == Z_STREAM_END)
2792 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002793 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002794 png_ptr->idat_size)
Guy Schalnat6d764711995-12-19 03:22:19 -06002795 png_error(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002796 png_ptr->mode |= PNG_AFTER_IDAT;
2797 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002798 break;
2799 }
2800 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002801 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05002802 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05002803
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002804 if (!(png_ptr->zstream.avail_out))
Guy Schalnat6d764711995-12-19 03:22:19 -06002805 png_error(png_ptr, "Extra compressed data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002806
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002807 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002808 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002809 }
2810
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002811 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Guy Schalnat6d764711995-12-19 03:22:19 -06002812 png_error(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002813
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002814 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05002815
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002816 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002817}
2818
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002819void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06002820png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002821{
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002822#ifdef PNG_USE_LOCAL_ARRAYS
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002823 /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002824
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002825 /* start of interlace block */
2826 const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002827
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002828 /* offset to next interlace block */
2829 const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002830
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002831 /* start of interlace block in the y direction */
2832 const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002833
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -06002834 /* offset to next interlace block in the y direction */
2835 const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
Glenn Randers-Pehrson074af5e1999-11-28 23:32:18 -06002836#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002837
Guy Schalnat0d580581995-07-20 02:43:20 -05002838 int max_pixel_depth;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002839 png_uint_32 row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05002840
Andreas Dilger47a0c421997-05-16 02:46:07 -05002841 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002842 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002843 png_init_read_transformations(png_ptr);
2844 if (png_ptr->interlaced)
2845 {
2846 if (!(png_ptr->transformations & PNG_INTERLACE))
2847 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
2848 png_pass_ystart[0]) / png_pass_yinc[0];
2849 else
2850 png_ptr->num_rows = png_ptr->height;
2851
2852 png_ptr->iwidth = (png_ptr->width +
2853 png_pass_inc[png_ptr->pass] - 1 -
2854 png_pass_start[png_ptr->pass]) /
2855 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002856
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002857 row_bytes = ((png_ptr->iwidth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002858 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002859 png_ptr->irowbytes = (png_size_t)row_bytes;
2860 if((png_uint_32)png_ptr->irowbytes != row_bytes)
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002861 png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002862 }
2863 else
2864 {
2865 png_ptr->num_rows = png_ptr->height;
2866 png_ptr->iwidth = png_ptr->width;
2867 png_ptr->irowbytes = png_ptr->rowbytes + 1;
2868 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002869 max_pixel_depth = png_ptr->pixel_depth;
2870
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002871#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002872 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002873 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002874#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002875
Guy Schalnate5a37791996-06-05 15:50:50 -05002876#if defined(PNG_READ_EXPAND_SUPPORTED)
2877 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002878 {
2879 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2880 {
2881 if (png_ptr->num_trans)
2882 max_pixel_depth = 32;
2883 else
2884 max_pixel_depth = 24;
2885 }
2886 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
2887 {
2888 if (max_pixel_depth < 8)
2889 max_pixel_depth = 8;
2890 if (png_ptr->num_trans)
2891 max_pixel_depth *= 2;
2892 }
2893 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2894 {
2895 if (png_ptr->num_trans)
2896 {
2897 max_pixel_depth *= 4;
2898 max_pixel_depth /= 3;
2899 }
2900 }
2901 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002902#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002903
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002904#if defined(PNG_READ_FILLER_SUPPORTED)
2905 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05002906 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002907 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2908 max_pixel_depth = 32;
2909 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002910 {
2911 if (max_pixel_depth <= 8)
2912 max_pixel_depth = 16;
2913 else
2914 max_pixel_depth = 32;
2915 }
2916 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2917 {
2918 if (max_pixel_depth <= 32)
2919 max_pixel_depth = 32;
2920 else
2921 max_pixel_depth = 64;
2922 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002923 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002924#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002925
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002926#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002927 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
2928 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002929 if (
2930#if defined(PNG_READ_EXPAND_SUPPORTED)
2931 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
2932#endif
2933#if defined(PNG_READ_FILLER_SUPPORTED)
2934 (png_ptr->transformations & (PNG_FILLER)) ||
2935#endif
2936 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05002937 {
2938 if (max_pixel_depth <= 16)
2939 max_pixel_depth = 32;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002940 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002941 max_pixel_depth = 64;
2942 }
2943 else
2944 {
2945 if (max_pixel_depth <= 8)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06002946 {
2947 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2948 max_pixel_depth = 32;
2949 else
2950 max_pixel_depth = 24;
2951 }
2952 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2953 max_pixel_depth = 64;
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06002954 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002955 max_pixel_depth = 48;
2956 }
2957 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002958#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002959
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002960#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
2961defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05002962 if(png_ptr->transformations & PNG_USER_TRANSFORM)
2963 {
2964 int user_pixel_depth=png_ptr->user_transform_depth*
2965 png_ptr->user_transform_channels;
2966 if(user_pixel_depth > max_pixel_depth)
2967 max_pixel_depth=user_pixel_depth;
2968 }
2969#endif
2970
Guy Schalnat0d580581995-07-20 02:43:20 -05002971 /* align the width on the next larger 8 pixels. Mainly used
2972 for interlacing */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002973 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Guy Schalnat0d580581995-07-20 02:43:20 -05002974 /* calculate the maximum bytes needed, adding a byte and a pixel
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05002975 for safety's sake */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002976 row_bytes = ((row_bytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
Guy Schalnat0d580581995-07-20 02:43:20 -05002977 1 + ((max_pixel_depth + 7) >> 3);
2978#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002979 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002980 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002981#endif
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05002982 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, row_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002983
2984#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002985 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002986 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002987#endif
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002988 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
2989 png_ptr->rowbytes + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002990
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002991 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002992
Glenn Randers-Pehrson4766a242000-07-17 06:17:09 -05002993 png_debug1(3, "width = %lu,\n", png_ptr->width);
2994 png_debug1(3, "height = %lu,\n", png_ptr->height);
2995 png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
2996 png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
2997 png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
2998 png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002999
Guy Schalnate5a37791996-06-05 15:50:50 -05003000 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003001}