blob: a21a03fd30de76b7dcbae9d523d55ffc1d68dc58 [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-Pehrson397100e1998-03-07 19:45:37 -06004 * libpng 0.99
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06005 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
7 * Copyright (c) 1996, 1997 Andreas Dilger
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06008 * Copyright (c) 1998, Glenn Randers-Pehrson
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -06009 * March 7, 1998
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060010 *
11 * This file contains routines which are only called from within
12 * libpng itself during the course of reading an image.
13 */
Guy Schalnat0d580581995-07-20 02:43:20 -050014
15#define PNG_INTERNAL
16#include "png.h"
17
Andreas Dilger47a0c421997-05-16 02:46:07 -050018#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
19/* Grab an unsigned 32-bit integer from a buffer in big endian format. */
Guy Schalnat0d580581995-07-20 02:43:20 -050020png_uint_32
Guy Schalnat6d764711995-12-19 03:22:19 -060021png_get_uint_32(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050022{
23 png_uint_32 i;
24
25 i = ((png_uint_32)(*buf) << 24) +
26 ((png_uint_32)(*(buf + 1)) << 16) +
27 ((png_uint_32)(*(buf + 2)) << 8) +
28 (png_uint_32)(*(buf + 3));
29
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060030 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050031}
32
Andreas Dilger47a0c421997-05-16 02:46:07 -050033#if defined(PNG_READ_pCAL_SUPPORTED)
34/* Grab a signed 32-bit integer from a buffer in big endian format. The
35 * data is stored in the PNG file in two's complement format, and it is
36 * assumed that the machine format for signed integers is the same. */
37png_int_32
38png_get_int_32(png_bytep buf)
39{
40 png_int_32 i;
41
42 i = ((png_int_32)(*buf) << 24) +
43 ((png_int_32)(*(buf + 1)) << 16) +
44 ((png_int_32)(*(buf + 2)) << 8) +
45 (png_int_32)(*(buf + 3));
46
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060047 return (i);
Andreas Dilger47a0c421997-05-16 02:46:07 -050048}
49#endif /* PNG_READ_pCAL_SUPPORTED */
50
51/* Grab an unsigned 16-bit integer from a buffer in big endian format. */
Guy Schalnat0d580581995-07-20 02:43:20 -050052png_uint_16
Guy Schalnat6d764711995-12-19 03:22:19 -060053png_get_uint_16(png_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -050054{
55 png_uint_16 i;
56
Guy Schalnatb2e01bd1996-01-26 01:38:47 -060057 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
58 (png_uint_16)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -050059
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -060060 return (i);
Guy Schalnat0d580581995-07-20 02:43:20 -050061}
Andreas Dilger47a0c421997-05-16 02:46:07 -050062#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050063
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060064/* Read data, and (optionally) run it through the CRC. */
Guy Schalnat0d580581995-07-20 02:43:20 -050065void
Andreas Dilger47a0c421997-05-16 02:46:07 -050066png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -050067{
Guy Schalnat6d764711995-12-19 03:22:19 -060068 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -050069 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -050070}
71
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060072/* Optionally skip data and then check the CRC. Depending on whether we
73 are reading a ancillary or critical chunk, and how the program has set
Andreas Dilger47a0c421997-05-16 02:46:07 -050074 things up, we may calculate the CRC on the data and print a message.
75 Returns '1' if there was a CRC error, '0' otherwise. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060076int
77png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -050078{
79 png_uint_32 i;
80
Andreas Dilger47a0c421997-05-16 02:46:07 -050081 for (i = skip; i > (png_uint_32)png_ptr->zbuf_size; i -= png_ptr->zbuf_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060082 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050083 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -050084 }
85 if (i)
86 {
Andreas Dilger47a0c421997-05-16 02:46:07 -050087 png_crc_read(png_ptr, png_ptr->zbuf, (png_size_t)i);
Guy Schalnat0d580581995-07-20 02:43:20 -050088 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060089
Andreas Dilger47a0c421997-05-16 02:46:07 -050090 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060091 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060092 if ((png_ptr->chunk_name[0] & 0x20 && /* Ancillary */
93 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
94 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
95 png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
96 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -060097 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060098 }
99 else
100 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600101 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600102 }
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600103 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600104 }
105
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600106 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500107}
108
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600109/* Compare the CRC stored in the PNG file with that calculated by libpng from
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600110 the data it has read thus far. */
111int
112png_crc_error(png_structp png_ptr)
113{
114 png_byte crc_bytes[4];
115 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500116 int need_crc = 1;
117
118 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
119 {
120 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
121 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
122 need_crc = 0;
123 }
124 else /* critical */
125 {
126 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
127 need_crc = 0;
128 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600129
130 png_read_data(png_ptr, crc_bytes, 4);
131
Andreas Dilger47a0c421997-05-16 02:46:07 -0500132 if (need_crc)
133 {
134 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600135 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500136 }
137 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600138 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600139}
140
141
Guy Schalnat0d580581995-07-20 02:43:20 -0500142/* read and check the IDHR chunk */
143void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600144png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500145{
146 png_byte buf[13];
147 png_uint_32 width, height;
148 int bit_depth, color_type, compression_type, filter_type;
149 int interlace_type;
150
Andreas Dilger47a0c421997-05-16 02:46:07 -0500151 png_debug(1, "in png_handle_IHDR\n");
152
Guy Schalnate5a37791996-06-05 15:50:50 -0500153 if (png_ptr->mode != PNG_BEFORE_IHDR)
154 png_error(png_ptr, "Out of place IHDR");
155
Guy Schalnat0d580581995-07-20 02:43:20 -0500156 /* check the length */
157 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600158 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500159
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600160 png_ptr->mode |= PNG_HAVE_IHDR;
161
Guy Schalnat0d580581995-07-20 02:43:20 -0500162 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600163 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500164
165 width = png_get_uint_32(buf);
166 height = png_get_uint_32(buf + 4);
167 bit_depth = buf[8];
168 color_type = buf[9];
169 compression_type = buf[10];
170 filter_type = buf[11];
171 interlace_type = buf[12];
172
173 /* check for width and height valid values */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600174 if (width == 0 || width > (png_uint_32)2147483647L || height == 0 ||
175 height > (png_uint_32)2147483647L)
Guy Schalnate5a37791996-06-05 15:50:50 -0500176 png_error(png_ptr, "Invalid image size in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500177
178 /* check other values */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500179 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
180 bit_depth != 8 && bit_depth != 16)
Guy Schalnate5a37791996-06-05 15:50:50 -0500181 png_error(png_ptr, "Invalid bit depth in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500182
183 if (color_type < 0 || color_type == 1 ||
184 color_type == 5 || color_type > 6)
Guy Schalnate5a37791996-06-05 15:50:50 -0500185 png_error(png_ptr, "Invalid color type in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500186
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600187 if ((color_type == PNG_COLOR_TYPE_PALETTE && bit_depth) > 8 ||
188 ((color_type == PNG_COLOR_TYPE_RGB ||
189 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
190 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
191 png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500192
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600193 if (interlace_type >= PNG_INTERLACE_LAST)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600194 png_error(png_ptr, "Unknown interlace method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500195
Andreas Dilger47a0c421997-05-16 02:46:07 -0500196 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600197 png_error(png_ptr, "Unknown compression method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500198
Andreas Dilger47a0c421997-05-16 02:46:07 -0500199 if (filter_type != PNG_FILTER_TYPE_BASE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600200 png_error(png_ptr, "Unknown filter method in IHDR");
Guy Schalnat0d580581995-07-20 02:43:20 -0500201
202 /* set internal variables */
203 png_ptr->width = width;
204 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600205 png_ptr->bit_depth = (png_byte)bit_depth;
206 png_ptr->interlaced = (png_byte)interlace_type;
207 png_ptr->color_type = (png_byte)color_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500208
209 /* find number of channels */
210 switch (png_ptr->color_type)
211 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500212 case PNG_COLOR_TYPE_GRAY:
213 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500214 png_ptr->channels = 1;
215 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500216 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500217 png_ptr->channels = 3;
218 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500219 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500220 png_ptr->channels = 2;
221 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500222 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500223 png_ptr->channels = 4;
224 break;
225 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600226
Guy Schalnat0d580581995-07-20 02:43:20 -0500227 /* set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600228 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600229 png_ptr->channels);
Guy Schalnat0d580581995-07-20 02:43:20 -0500230 png_ptr->rowbytes = ((png_ptr->width *
231 (png_uint_32)png_ptr->pixel_depth + 7) >> 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500232 png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
233 png_debug1(3,"channels = %d\n", png_ptr->channels);
234 png_debug1(3,"rowbytes = %d\n", png_ptr->rowbytes);
235 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
236 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500237}
238
239/* read and check the palette */
240void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600241png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500242{
Guy Schalnat6d764711995-12-19 03:22:19 -0600243 png_colorp palette;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600244 int num, i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500245
Andreas Dilger47a0c421997-05-16 02:46:07 -0500246 png_debug(1, "in png_handle_PLTE\n");
247
Guy Schalnate5a37791996-06-05 15:50:50 -0500248 if (!(png_ptr->mode & PNG_HAVE_IHDR))
249 png_error(png_ptr, "Missing IHDR before PLTE");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600250 else if (png_ptr->mode & PNG_HAVE_IDAT)
251 {
252 png_warning(png_ptr, "Invalid PLTE after IDAT");
253 png_crc_finish(png_ptr, length);
254 return;
255 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500256 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600257 png_error(png_ptr, "Duplicate PLTE chunk");
258
259 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500260
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -0600261#if defined (PNG_READ_tRNS_SUPPORTED)
262 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
263 {
264 if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
265 {
266 if (png_ptr->num_trans > png_ptr->num_palette)
267 {
268 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
269 png_ptr->num_trans = png_ptr->num_palette;
270 }
271 }
272 }
273#endif
274
Guy Schalnate5a37791996-06-05 15:50:50 -0500275#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
276 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
277 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600278 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500279 return;
280 }
281#endif
282
Guy Schalnat0d580581995-07-20 02:43:20 -0500283 if (length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500284 {
285 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
286 {
287 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600288 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500289 return;
290 }
291 else
292 {
293 png_error(png_ptr, "Invalid palette chunk");
294 }
295 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500296
297 num = (int)length / 3;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600298 palette = (png_colorp)png_zalloc(png_ptr, (uInt)num, sizeof (png_color));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600299 png_ptr->flags |= PNG_FLAG_FREE_PALETTE;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600300 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500301 {
302 png_byte buf[3];
303
304 png_crc_read(png_ptr, buf, 3);
305 /* don't depend upon png_color being any order */
306 palette[i].red = buf[0];
307 palette[i].green = buf[1];
308 palette[i].blue = buf[2];
309 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600310
311 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
312 whatever the normal CRC configuration tells us. However, if we
313 have an RGB image, the PLTE can be considered ancillary, so
314 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600315#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600316 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600317#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600318 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500319 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600320 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600321#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600322 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
323 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600324 /* If we don't want to use the data from an ancillary chunk,
325 we have two options: an error abort, or a warning and we
326 ignore the data in this chunk (which should be OK, since
327 it's considered ancillary for a RGB or RGBA image). */
328 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
329 {
330 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
331 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600332 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600333 }
334 else
335 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600336 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500337 png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600338 png_zfree(png_ptr, palette);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600339 return;
340 }
341 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500342 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600343 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
344 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600345 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600346 }
347 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600348#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500349 png_ptr->palette = palette;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600350 png_ptr->num_palette = (png_uint_16)num;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500351 png_set_PLTE(png_ptr, info_ptr, palette, num);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600352}
Guy Schalnate5a37791996-06-05 15:50:50 -0500353
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600354void
355png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
356{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500357 png_debug(1, "in png_handle_IEND\n");
358
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600359 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
360 {
361 png_error(png_ptr, "No image in file");
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -0600362
363 /* to quiet compiler warnings about unused info_ptr */
364 if (info_ptr == NULL)
365 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600366 }
367
368 png_ptr->mode |= PNG_AFTER_IDAT | PNG_HAVE_IEND;
369
370 if (length != 0)
371 {
372 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600373 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500374 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500375}
376
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500377#if defined(PNG_READ_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500378void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600379png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500380{
381 png_uint_32 igamma;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500382 float file_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500383 png_byte buf[4];
384
Andreas Dilger47a0c421997-05-16 02:46:07 -0500385 png_debug(1, "in png_handle_gAMA\n");
386
Guy Schalnate5a37791996-06-05 15:50:50 -0500387 if (!(png_ptr->mode & PNG_HAVE_IHDR))
388 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600389 else if (png_ptr->mode & PNG_HAVE_IDAT)
390 {
391 png_warning(png_ptr, "Invalid gAMA after IDAT");
392 png_crc_finish(png_ptr, length);
393 return;
394 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500395 else if (png_ptr->mode & PNG_HAVE_PLTE)
396 /* Should be an error, but we can cope with it */
397 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600398
399 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA
400#if defined(PNG_READ_sRGB_SUPPORTED)
401 && !(info_ptr->valid & PNG_INFO_sRGB)
402#endif
403 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600404 {
405 png_warning(png_ptr, "Duplicate gAMA chunk");
406 png_crc_finish(png_ptr, length);
407 return;
408 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500409
Guy Schalnat0d580581995-07-20 02:43:20 -0500410 if (length != 4)
411 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600412 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600413 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500414 return;
415 }
416
417 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600418 if (png_crc_finish(png_ptr, 0))
419 return;
420
Guy Schalnat0d580581995-07-20 02:43:20 -0500421 igamma = png_get_uint_32(buf);
422 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500423 if (igamma == 0)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600424 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500425
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600426#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600427 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600428 if(igamma != (png_uint_32)45000L)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600429 {
430 png_warning(png_ptr,
431 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600432#ifndef PNG_NO_STDIO
433 fprintf(stderr, "igamma = %lu\n", igamma);
434#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600435 return;
436 }
437#endif /* PNG_READ_sRGB_SUPPORTED */
438
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600439 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600440#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500441 png_ptr->gamma = file_gamma;
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600442#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500443 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500444}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500445#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500446
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500447#if defined(PNG_READ_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500448void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600449png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500450{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500451 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600452 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600453
Andreas Dilger47a0c421997-05-16 02:46:07 -0500454 png_debug(1, "in png_handle_sBIT\n");
455
Guy Schalnat69b14481996-01-10 02:56:49 -0600456 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500457
Guy Schalnate5a37791996-06-05 15:50:50 -0500458 if (!(png_ptr->mode & PNG_HAVE_IHDR))
459 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600460 else if (png_ptr->mode & PNG_HAVE_IDAT)
461 {
462 png_warning(png_ptr, "Invalid sBIT after IDAT");
463 png_crc_finish(png_ptr, length);
464 return;
465 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500466 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600467 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500468 /* Should be an error, but we can cope with it */
469 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600470 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500471 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600472 {
473 png_warning(png_ptr, "Duplicate sBIT chunk");
474 png_crc_finish(png_ptr, length);
475 return;
476 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500477
Guy Schalnat0d580581995-07-20 02:43:20 -0500478 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600479 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500480 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500481 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500482
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600483 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500484 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600485 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600486 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600487 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500488 }
489
Andreas Dilger47a0c421997-05-16 02:46:07 -0500490 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600491 if (png_crc_finish(png_ptr, 0))
492 return;
493
Guy Schalnat0d580581995-07-20 02:43:20 -0500494 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
495 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600496 png_ptr->sig_bit.red = buf[0];
497 png_ptr->sig_bit.green = buf[1];
498 png_ptr->sig_bit.blue = buf[2];
499 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500500 }
501 else
502 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600503 png_ptr->sig_bit.gray = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600504 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500505 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500506 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500507}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500508#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500509
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500510#if defined(PNG_READ_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500511void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600512png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500513{
514 png_byte buf[4];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600515 png_uint_32 val;
Guy Schalnat0d580581995-07-20 02:43:20 -0500516 float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
517
Andreas Dilger47a0c421997-05-16 02:46:07 -0500518 png_debug(1, "in png_handle_cHRM\n");
519
Guy Schalnate5a37791996-06-05 15:50:50 -0500520 if (!(png_ptr->mode & PNG_HAVE_IHDR))
521 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600522 else if (png_ptr->mode & PNG_HAVE_IDAT)
523 {
524 png_warning(png_ptr, "Invalid cHRM after IDAT");
525 png_crc_finish(png_ptr, length);
526 return;
527 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500528 else if (png_ptr->mode & PNG_HAVE_PLTE)
529 /* Should be an error, but we can cope with it */
530 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600531
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600532 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600533#if defined(PNG_READ_sRGB_SUPPORTED)
534 && !(info_ptr->valid & PNG_INFO_sRGB)
535#endif
536 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600537 {
538 png_warning(png_ptr, "Duplicate cHRM chunk");
539 png_crc_finish(png_ptr, length);
540 return;
541 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500542
Guy Schalnat0d580581995-07-20 02:43:20 -0500543 if (length != 32)
544 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600545 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600546 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600547 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500548 }
549
550 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600551 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600552 white_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500553
554 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600555 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600556 white_y = (float)val / (float)100000.0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600557
558 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
559 white_x + white_y > 1.0)
560 {
561 png_warning(png_ptr, "Invalid cHRM white point");
562 png_crc_finish(png_ptr, 24);
563 return;
564 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500565
566 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600567 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600568 red_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500569
570 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600571 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600572 red_y = (float)val / (float)100000.0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600573
574 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
575 red_x + red_y > 1.0)
576 {
577 png_warning(png_ptr, "Invalid cHRM red point");
578 png_crc_finish(png_ptr, 16);
579 return;
580 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500581
582 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600583 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600584 green_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500585
586 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600587 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600588 green_y = (float)val / (float)100000.0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600589
590 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
591 green_x + green_y > 1.0)
592 {
593 png_warning(png_ptr, "Invalid cHRM green point");
594 png_crc_finish(png_ptr, 8);
595 return;
596 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500597
598 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600599 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600600 blue_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500601
602 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600603 val = png_get_uint_32(buf);
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600604 blue_y = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500605
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600606 if (blue_x < (float)0 || blue_x > (float)0.8 || blue_y < (float)0 ||
607 blue_y > (float)0.8 || blue_x + blue_y > (float)1.0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600608 {
609 png_warning(png_ptr, "Invalid cHRM blue point");
610 png_crc_finish(png_ptr, 0);
611 return;
612 }
613
614 if (png_crc_finish(png_ptr, 0))
615 return;
616
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600617#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600618 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600619 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600620 if (fabs(white_x - (float).3127) > (float).001 ||
621 fabs(white_y - (float).3290) > (float).001 ||
622 fabs( red_x - (float).6400) > (float).001 ||
623 fabs( red_y - (float).3300) > (float).001 ||
624 fabs(green_x - (float).3000) > (float).001 ||
625 fabs(green_y - (float).6000) > (float).001 ||
626 fabs( blue_x - (float).1500) > (float).001 ||
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600627 fabs( blue_y - (float).0600) > (float).001)
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600628 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600629
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600630 png_warning(png_ptr,
631 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600632#ifndef PNG_NO_STDIO
633 fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
634 white_x, white_y, red_x, red_y);
635 fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
636 green_x, green_y, blue_x, blue_y);
637#endif
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600638 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600639 return;
640 }
641#endif /* PNG_READ_sRGB_SUPPORTED */
642
Andreas Dilger47a0c421997-05-16 02:46:07 -0500643 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600644 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Guy Schalnat0d580581995-07-20 02:43:20 -0500645}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500646#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500647
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600648#if defined(PNG_READ_sRGB_SUPPORTED)
649void
650png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
651{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600652 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600653 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600654
655 png_debug(1, "in png_handle_sRGB\n");
656
657 if (!(png_ptr->mode & PNG_HAVE_IHDR))
658 png_error(png_ptr, "Missing IHDR before sRGB");
659 else if (png_ptr->mode & PNG_HAVE_IDAT)
660 {
661 png_warning(png_ptr, "Invalid sRGB after IDAT");
662 png_crc_finish(png_ptr, length);
663 return;
664 }
665 else if (png_ptr->mode & PNG_HAVE_PLTE)
666 /* Should be an error, but we can cope with it */
667 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600668
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600669 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sRGB)
670 {
671 png_warning(png_ptr, "Duplicate sRGB chunk");
672 png_crc_finish(png_ptr, length);
673 return;
674 }
675
676 if (length != 1)
677 {
678 png_warning(png_ptr, "Incorrect sRGB chunk length");
679 png_crc_finish(png_ptr, length);
680 return;
681 }
682
683 png_crc_read(png_ptr, buf, 1);
684 if (png_crc_finish(png_ptr, 0))
685 return;
686
687 intent = buf[0];
688 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600689 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600690 {
691 png_warning(png_ptr, "Unknown sRGB intent");
692 return;
693 }
694
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600695#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600696 if ((info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson397100e1998-03-07 19:45:37 -0600697 if((png_uint_32)(png_ptr->gamma*(float)100000.+.5) != (png_uint_32)45000L)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600698 {
699 png_warning(png_ptr,
700 "Ignoring incorrect gAMA value when sRGB is also present");
701#ifndef PNG_NO_STDIO
702 fprintf(stderr,"gamma=%f\n",png_ptr->gamma);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600703#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600704 }
705#endif /* PNG_READ_gAMA_SUPPORTED */
706
707#ifdef PNG_READ_cHRM_SUPPORTED
708 if (info_ptr->valid & PNG_INFO_cHRM)
709 if (fabs(info_ptr->x_white - (float).3127) > (float).001 ||
710 fabs(info_ptr->y_white - (float).3290) > (float).001 ||
711 fabs( info_ptr->x_red - (float).6400) > (float).001 ||
712 fabs( info_ptr->y_red - (float).3300) > (float).001 ||
713 fabs(info_ptr->x_green - (float).3000) > (float).001 ||
714 fabs(info_ptr->y_green - (float).6000) > (float).001 ||
715 fabs( info_ptr->x_blue - (float).1500) > (float).001 ||
716 fabs( info_ptr->y_blue - (float).0600) > (float).001)
717 {
718 png_warning(png_ptr,
719 "Ignoring incorrect cHRM value when sRGB is also present");
720 }
721#endif /* PNG_READ_cHRM_SUPPORTED */
722
723 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
724}
725#endif /* PNG_READ_sRGB_SUPPORTED */
726
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500727#if defined(PNG_READ_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500728void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600729png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500730{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500731 png_debug(1, "in png_handle_tRNS\n");
732
Guy Schalnate5a37791996-06-05 15:50:50 -0500733 if (!(png_ptr->mode & PNG_HAVE_IHDR))
734 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600735 else if (png_ptr->mode & PNG_HAVE_IDAT)
736 {
737 png_warning(png_ptr, "Invalid tRNS after IDAT");
738 png_crc_finish(png_ptr, length);
739 return;
740 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500741 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600742 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -0600743 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600744 png_crc_finish(png_ptr, length);
745 return;
746 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500747
Guy Schalnat0d580581995-07-20 02:43:20 -0500748 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
749 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500750 if (!(png_ptr->mode & PNG_HAVE_PLTE))
751 {
752 /* Should be an error, but we can cope with it */
753 png_warning(png_ptr, "Missing PLTE before tRNS");
754 }
755 else if (length > png_ptr->num_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500756 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600757 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600758 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500759 return;
760 }
761
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600762 png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
763 png_ptr->flags |= PNG_FLAG_FREE_TRANS;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500764 png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600765 png_ptr->num_trans = (png_uint_16)length;
Guy Schalnat0d580581995-07-20 02:43:20 -0500766 }
767 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
768 {
769 png_byte buf[6];
770
771 if (length != 6)
772 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600773 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600774 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500775 return;
776 }
777
Andreas Dilger47a0c421997-05-16 02:46:07 -0500778 png_crc_read(png_ptr, buf, (png_size_t)length);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600779 png_ptr->num_trans = 1;
Guy Schalnat0d580581995-07-20 02:43:20 -0500780 png_ptr->trans_values.red = png_get_uint_16(buf);
781 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
782 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
783 }
784 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
785 {
786 png_byte buf[6];
787
788 if (length != 2)
789 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600790 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600791 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600792 return;
793 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500794
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600795 png_crc_read(png_ptr, buf, 2);
796 png_ptr->num_trans = 1;
797 png_ptr->trans_values.gray = png_get_uint_16(buf);
798 }
799 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500800 {
801 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600802 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500803 return;
804 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500805
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600806 if (png_crc_finish(png_ptr, 0))
807 return;
808
Andreas Dilger47a0c421997-05-16 02:46:07 -0500809 png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -0500810 &(png_ptr->trans_values));
811}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500812#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500813
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500814#if defined(PNG_READ_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500815void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600816png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500817{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500818 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -0500819 png_byte buf[6];
820
Andreas Dilger47a0c421997-05-16 02:46:07 -0500821 png_debug(1, "in png_handle_bKGD\n");
822
Guy Schalnate5a37791996-06-05 15:50:50 -0500823 if (!(png_ptr->mode & PNG_HAVE_IHDR))
824 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600825 else if (png_ptr->mode & PNG_HAVE_IDAT)
826 {
827 png_warning(png_ptr, "Invalid bKGD after IDAT");
828 png_crc_finish(png_ptr, length);
829 return;
830 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500831 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
832 !(png_ptr->mode & PNG_HAVE_PLTE))
833 {
834 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600835 png_crc_finish(png_ptr, length);
836 return;
837 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500838 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600839 {
840 png_warning(png_ptr, "Duplicate bKGD chunk");
841 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500842 return;
843 }
844
Guy Schalnat0d580581995-07-20 02:43:20 -0500845 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
846 truelen = 1;
847 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
848 truelen = 6;
849 else
850 truelen = 2;
851
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600852 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500853 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600854 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600855 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500856 return;
857 }
858
Andreas Dilger47a0c421997-05-16 02:46:07 -0500859 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600860 if (png_crc_finish(png_ptr, 0))
861 return;
862
Guy Schalnate5a37791996-06-05 15:50:50 -0500863 /* We convert the index value into RGB components so that we can allow
864 * arbitrary RGB values for background when we have transparency, and
865 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600866 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500867 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500868 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500869 png_ptr->background.index = buf[0];
Guy Schalnate5a37791996-06-05 15:50:50 -0500870 png_ptr->background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
871 png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
872 png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
873 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500874 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -0500875 {
876 png_ptr->background.red =
877 png_ptr->background.green =
878 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500879 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -0500880 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500881 else
882 {
883 png_ptr->background.red = png_get_uint_16(buf);
884 png_ptr->background.green = png_get_uint_16(buf + 2);
885 png_ptr->background.blue = png_get_uint_16(buf + 4);
886 }
887
Andreas Dilger47a0c421997-05-16 02:46:07 -0500888 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -0500889}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500890#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500891
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500892#if defined(PNG_READ_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500893void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600894png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500895{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600896 int num, i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500897
Andreas Dilger47a0c421997-05-16 02:46:07 -0500898 png_debug(1, "in png_handle_hIST\n");
899
Guy Schalnate5a37791996-06-05 15:50:50 -0500900 if (!(png_ptr->mode & PNG_HAVE_IHDR))
901 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600902 else if (png_ptr->mode & PNG_HAVE_IDAT)
903 {
904 png_warning(png_ptr, "Invalid hIST after IDAT");
905 png_crc_finish(png_ptr, length);
906 return;
907 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500908 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
909 {
910 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600911 png_crc_finish(png_ptr, length);
912 return;
913 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500914 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600915 {
916 png_warning(png_ptr, "Duplicate hIST chunk");
917 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500918 return;
919 }
920
Andreas Dilger47a0c421997-05-16 02:46:07 -0500921 if (length != (png_uint_32)(2 * png_ptr->num_palette))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600922 {
923 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600924 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600925 return;
926 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500927
928 num = (int)length / 2;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600929 png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600930 (png_uint_32)(num * sizeof (png_uint_16)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600931 png_ptr->flags |= PNG_FLAG_FREE_HIST;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600932 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500933 {
934 png_byte buf[2];
935
936 png_crc_read(png_ptr, buf, 2);
937 png_ptr->hist[i] = png_get_uint_16(buf);
938 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600939
940 if (png_crc_finish(png_ptr, 0))
941 return;
942
Andreas Dilger47a0c421997-05-16 02:46:07 -0500943 png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
Guy Schalnat0d580581995-07-20 02:43:20 -0500944}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500945#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500946
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500947#if defined(PNG_READ_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500948void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600949png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500950{
951 png_byte buf[9];
952 png_uint_32 res_x, res_y;
953 int unit_type;
954
Andreas Dilger47a0c421997-05-16 02:46:07 -0500955 png_debug(1, "in png_handle_pHYs\n");
956
Guy Schalnate5a37791996-06-05 15:50:50 -0500957 if (!(png_ptr->mode & PNG_HAVE_IHDR))
958 png_error(png_ptr, "Missing IHDR before pHYS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600959 else if (png_ptr->mode & PNG_HAVE_IDAT)
960 {
961 png_warning(png_ptr, "Invalid pHYS after IDAT");
962 png_crc_finish(png_ptr, length);
963 return;
964 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500965 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600966 {
967 png_warning(png_ptr, "Duplicate pHYS chunk");
968 png_crc_finish(png_ptr, length);
969 return;
970 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500971
Guy Schalnat0d580581995-07-20 02:43:20 -0500972 if (length != 9)
973 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600974 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600975 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500976 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600977 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500978
979 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600980 if (png_crc_finish(png_ptr, 0))
981 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500982
983 res_x = png_get_uint_32(buf);
984 res_y = png_get_uint_32(buf + 4);
985 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500986 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500987}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500988#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500989
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500990#if defined(PNG_READ_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500991void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600992png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500993{
994 png_byte buf[9];
995 png_uint_32 offset_x, offset_y;
996 int unit_type;
997
Andreas Dilger47a0c421997-05-16 02:46:07 -0500998 png_debug(1, "in png_handle_oFFs\n");
999
Guy Schalnate5a37791996-06-05 15:50:50 -05001000 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1001 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001002 else if (png_ptr->mode & PNG_HAVE_IDAT)
1003 {
1004 png_warning(png_ptr, "Invalid oFFs after IDAT");
1005 png_crc_finish(png_ptr, length);
1006 return;
1007 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001008 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001009 {
1010 png_warning(png_ptr, "Duplicate oFFs chunk");
1011 png_crc_finish(png_ptr, length);
1012 return;
1013 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001014
Guy Schalnat0d580581995-07-20 02:43:20 -05001015 if (length != 9)
1016 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001017 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001018 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001019 return;
1020 }
1021
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001022 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001023 if (png_crc_finish(png_ptr, 0))
1024 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001025
1026 offset_x = png_get_uint_32(buf);
1027 offset_y = png_get_uint_32(buf + 4);
1028 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001029 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1030}
1031#endif
1032
1033#if defined(PNG_READ_pCAL_SUPPORTED)
1034/* read the pCAL chunk (png-scivis-19970203) */
1035void
1036png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1037{
1038 png_charp purpose;
1039 png_int_32 X0, X1;
1040 png_byte type, nparams;
1041 png_charp buf, units, endptr;
1042 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001043 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001044 int i;
1045
1046 png_debug(1, "in png_handle_pCAL\n");
1047
1048 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1049 png_error(png_ptr, "Missing IHDR before pCAL");
1050 else if (png_ptr->mode & PNG_HAVE_IDAT)
1051 {
1052 png_warning(png_ptr, "Invalid pCAL after IDAT");
1053 png_crc_finish(png_ptr, length);
1054 return;
1055 }
1056 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL)
1057 {
1058 png_warning(png_ptr, "Duplicate pCAL chunk");
1059 png_crc_finish(png_ptr, length);
1060 return;
1061 }
1062
1063 png_debug1(2, "Allocating and reading pCAL chunk data (%d bytes)\n",
1064 length + 1);
1065 purpose = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001066 slength = (png_size_t)length;
1067 png_crc_read(png_ptr, (png_bytep)purpose, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001068
1069 if (png_crc_finish(png_ptr, 0))
1070 {
1071 png_free(png_ptr, purpose);
1072 return;
1073 }
1074
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001075 purpose[slength] = 0x00; /* null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001076
1077 png_debug(3, "Finding end of pCAL purpose string\n");
1078 for (buf = purpose; *buf != '\0'; buf++)
1079 /* empty loop */;
1080
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001081 endptr = purpose + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001082
1083 /* We need to have at least 12 bytes after the purpose string
1084 in order to get the parameter information. */
1085 if (endptr <= buf + 12)
1086 {
1087 png_warning(png_ptr, "Invalid pCAL data");
1088 png_free(png_ptr, purpose);
1089 return;
1090 }
1091
1092 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1093 X0 = png_get_int_32((png_bytep)buf+1);
1094 X1 = png_get_int_32((png_bytep)buf+5);
1095 type = buf[9];
1096 nparams = buf[10];
1097 units = buf + 11;
1098
1099 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1100 /* Check that we have the right number of parameters for known
1101 equation types. */
1102 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1103 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1104 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1105 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1106 {
1107 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
1108 png_free(png_ptr, purpose);
1109 return;
1110 }
1111 else if (type >= PNG_EQUATION_LAST)
1112 {
1113 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1114 }
1115
1116 /* Empty loop to move past the units string. */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001117 for (buf = units; *buf != 0x00; buf++);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001118
1119 png_debug(3, "Allocating pCAL parameters array\n");
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001120 params = (png_charpp)png_malloc(png_ptr, (png_uint_32)(nparams
1121 *sizeof(png_charp))) ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001122
1123 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001124 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001125 {
1126 buf++; /* Skip the null string terminator from previous parameter. */
1127
1128 png_debug1(3, "Reading pCAL parameter %d\n", i);
1129 /* Empty loop to move past each paramter string */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001130 for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001131
1132 /* Make sure we haven't run out of data yet */
1133 if (buf > endptr)
1134 {
1135 png_warning(png_ptr, "Invalid pCAL data");
1136 png_free(png_ptr, purpose);
1137 png_free(png_ptr, params);
1138 return;
1139 }
1140 }
1141
1142 png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
1143 units, params);
1144
1145 png_free(png_ptr, purpose);
1146 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001147}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001148#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001149
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001150#if defined(PNG_READ_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001151void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001152png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001153{
1154 png_byte buf[7];
1155 png_time mod_time;
1156
Andreas Dilger47a0c421997-05-16 02:46:07 -05001157 png_debug(1, "in png_handle_tIME\n");
1158
Guy Schalnate5a37791996-06-05 15:50:50 -05001159 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001160 png_error(png_ptr, "Out of place tIME chunk");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001161 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001162 {
1163 png_warning(png_ptr, "Duplicate tIME chunk");
1164 png_crc_finish(png_ptr, length);
1165 return;
1166 }
1167
1168 if (png_ptr->mode & PNG_HAVE_IDAT)
1169 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001170
Guy Schalnat0d580581995-07-20 02:43:20 -05001171 if (length != 7)
1172 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001173 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001174 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001175 return;
1176 }
1177
1178 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001179 if (png_crc_finish(png_ptr, 0))
1180 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001181
1182 mod_time.second = buf[6];
1183 mod_time.minute = buf[5];
1184 mod_time.hour = buf[4];
1185 mod_time.day = buf[3];
1186 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001187 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001188
Andreas Dilger47a0c421997-05-16 02:46:07 -05001189 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001190}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001191#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001192
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001193#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001194/* Note: this does not properly handle chunks that are > 64K under DOS */
Guy Schalnat0d580581995-07-20 02:43:20 -05001195void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001196png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001197{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001198 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001199 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001200 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001201 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001202 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001203
1204 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001205
Guy Schalnate5a37791996-06-05 15:50:50 -05001206 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1207 png_error(png_ptr, "Missing IHDR before tEXt");
1208
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001209 if (png_ptr->mode & PNG_HAVE_IDAT)
1210 png_ptr->mode |= PNG_AFTER_IDAT;
1211
Andreas Dilger47a0c421997-05-16 02:46:07 -05001212#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001213 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001214 {
1215 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001216 skip = length - (png_uint_32)65535L;
1217 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001218 }
1219#endif
1220
1221 key = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001222 slength = (png_size_t)length;
1223 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001224
1225 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001226 {
1227 png_free(png_ptr, key);
1228 return;
1229 }
1230
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001231 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001232
1233 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001234 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001235
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001236 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001237 text++;
1238
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001239 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001240 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1241 text_ptr->key = key;
1242 text_ptr->text = text;
1243
1244 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1245
1246 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001247}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001248#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001249
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001250#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001251/* note: this does not correctly handle chunks that are > 64K under DOS */
Guy Schalnat0d580581995-07-20 02:43:20 -05001252void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001253png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001254{
Guy Schalnate5a37791996-06-05 15:50:50 -05001255 static char msg[] = "Error decoding zTXt chunk";
Andreas Dilger47a0c421997-05-16 02:46:07 -05001256 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06001257 png_charp key;
1258 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001259 int comp_type = PNG_TEXT_COMPRESSION_NONE;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001260 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001261
1262 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001263
Guy Schalnate5a37791996-06-05 15:50:50 -05001264 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1265 png_error(png_ptr, "Missing IHDR before zTXt");
1266
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001267 if (png_ptr->mode & PNG_HAVE_IDAT)
1268 png_ptr->mode |= PNG_AFTER_IDAT;
1269
Andreas Dilger47a0c421997-05-16 02:46:07 -05001270#ifdef PNG_MAX_MALLOC_64K
1271 /* We will no doubt have problems with chunks even half this size, but
1272 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001273 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001274 {
1275 png_warning(png_ptr,"zTXt chunk too large to fit in memory");
1276 png_crc_finish(png_ptr, length);
1277 return;
1278 }
1279#endif
1280
1281 key = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001282 slength = (png_size_t)length;
1283 png_crc_read(png_ptr, (png_bytep)key, slength);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001284 if (png_crc_finish(png_ptr, 0))
1285 {
1286 png_free(png_ptr, key);
1287 return;
1288 }
1289
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001290 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05001291
1292 for (text = key; *text; text++)
1293 /* empty loop */ ;
1294
Andreas Dilger47a0c421997-05-16 02:46:07 -05001295 /* zTXt must have some text after the keyword */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001296 if (text == key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05001297 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001298 png_warning(png_ptr, "Zero length zTXt chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001299 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001300 else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt)
Guy Schalnat0d580581995-07-20 02:43:20 -05001301 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001302 png_size_t text_size, key_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001303 text++;
Guy Schalnat0d580581995-07-20 02:43:20 -05001304
Andreas Dilger47a0c421997-05-16 02:46:07 -05001305 png_ptr->zstream.next_in = (png_bytep)text;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001306 png_ptr->zstream.avail_in = (uInt)(length - (text - key));
1307 png_ptr->zstream.next_out = png_ptr->zbuf;
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001308 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001309
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001310 key_size = (png_size_t)(text - key);
Guy Schalnate5a37791996-06-05 15:50:50 -05001311 text_size = 0;
1312 text = NULL;
1313
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001314 while (png_ptr->zstream.avail_in)
Guy Schalnate5a37791996-06-05 15:50:50 -05001315 {
1316 int ret;
1317
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001318 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnate5a37791996-06-05 15:50:50 -05001319 if (ret != Z_OK && ret != Z_STREAM_END)
Guy Schalnat0d580581995-07-20 02:43:20 -05001320 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001321 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001322 png_warning(png_ptr, png_ptr->zstream.msg);
Guy Schalnate5a37791996-06-05 15:50:50 -05001323 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001324 png_warning(png_ptr, msg);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001325 inflateReset(&png_ptr->zstream);
1326 png_ptr->zstream.avail_in = 0;
Guy Schalnate5a37791996-06-05 15:50:50 -05001327
Andreas Dilger47a0c421997-05-16 02:46:07 -05001328 if (text == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001329 {
1330 text_size = key_size + sizeof(msg) + 1;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001331 text = (png_charp)png_malloc(png_ptr, (png_uint_32)text_size);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001332 png_memcpy(text, key, key_size);
Guy Schalnate5a37791996-06-05 15:50:50 -05001333 }
1334
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001335 text[text_size - 1] = 0x00;
Guy Schalnate5a37791996-06-05 15:50:50 -05001336
1337 /* Copy what we can of the error message into the text chunk */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001338 text_size = (png_size_t)(slength - (text - key) - 1);
Guy Schalnate5a37791996-06-05 15:50:50 -05001339 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001340 png_memcpy(text + key_size, msg, text_size + 1);
Guy Schalnate5a37791996-06-05 15:50:50 -05001341 break;
1342 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001343 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
Guy Schalnate5a37791996-06-05 15:50:50 -05001344 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001345 if (text == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001346 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001347 text = (png_charp)png_malloc(png_ptr,
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001348 (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
1349 + key_size + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001350 png_memcpy(text + key_size, png_ptr->zbuf,
1351 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
1352 png_memcpy(text, key, key_size);
1353 text_size = key_size + png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001354 png_ptr->zstream.avail_out;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001355 *(text + text_size) = 0x00;
Guy Schalnate5a37791996-06-05 15:50:50 -05001356 }
1357 else
1358 {
1359 png_charp tmp;
1360
1361 tmp = text;
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001362 text = (png_charp)png_malloc(png_ptr, (png_uint_32)(text_size +
1363 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001364 png_memcpy(text, tmp, text_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001365 png_free(png_ptr, tmp);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001366 png_memcpy(text + text_size, png_ptr->zbuf,
1367 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001368 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001369 *(text + text_size) = 0x00;
Guy Schalnate5a37791996-06-05 15:50:50 -05001370 }
1371 if (ret != Z_STREAM_END)
1372 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001373 png_ptr->zstream.next_out = png_ptr->zbuf;
1374 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001375 }
1376 else
1377 {
1378 break;
1379 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001380 }
1381 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001382
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001383 inflateReset(&png_ptr->zstream);
1384 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05001385
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001386 png_free(png_ptr, key);
Guy Schalnate5a37791996-06-05 15:50:50 -05001387 key = text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001388 text += key_size;
Guy Schalnat0d580581995-07-20 02:43:20 -05001389 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001390 else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */
1391 {
1392 png_size_t text_size;
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001393#if !defined(PNG_NO_STDIO)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001394 char umsg[50];
Guy Schalnat0d580581995-07-20 02:43:20 -05001395
Andreas Dilger47a0c421997-05-16 02:46:07 -05001396 sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
1397 png_warning(png_ptr, umsg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001398#else
1399 png_warning(png_ptr, "Unknown zTXt compression type");
1400#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001401
1402 /* Copy what we can of the error message into the text chunk */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001403 text_size = (png_size_t)(slength - (text - key) - 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001404 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
1405 png_memcpy(text, msg, text_size + 1);
1406 }
1407
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001408 text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text));
Andreas Dilger47a0c421997-05-16 02:46:07 -05001409 text_ptr->compression = comp_type;
1410 text_ptr->key = key;
1411 text_ptr->text = text;
1412
1413 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1414
1415 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001416}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001417#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001418
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001419/* This function is called when we haven't found a handler for a
1420 chunk. If there isn't a problem with the chunk itself (ie bad
Andreas Dilger47a0c421997-05-16 02:46:07 -05001421 chunk name, CRC, or a critical chunk), the chunk is silently ignored. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001422void
1423png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1424{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001425 png_debug(1, "in png_handle_unknown\n");
1426
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001427 /* In the future we can have code here that calls user-supplied
1428 * callback functions for unknown chunks before they are ignored or
1429 * cause an error.
1430 */
1431 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
1432
1433 if (!(png_ptr->chunk_name[0] & 0x20))
1434 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001435 png_chunk_error(png_ptr, "unknown critical chunk");
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001436
Glenn Randers-Pehrsoncbe52d81998-02-28 07:00:24 -06001437 /* to quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001438 if (info_ptr == NULL)
1439 return;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001440 }
1441
1442 if (png_ptr->mode & PNG_HAVE_IDAT)
1443 png_ptr->mode |= PNG_AFTER_IDAT;
1444
1445 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001446
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001447}
1448
1449/* This function is called to verify that a chunk name is valid.
1450 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05001451 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001452 functions to handle unknown critical chunks after we check that
1453 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001454
1455#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
1456
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001457void
1458png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
1459{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001460 png_debug(1, "in png_check_chunk_name\n");
1461 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
1462 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001463 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001464 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001465 }
1466}
1467
Guy Schalnat0d580581995-07-20 02:43:20 -05001468/* Combines the row recently read in with the previous row.
1469 This routine takes care of alpha and transparency if requested.
1470 This routine also handles the two methods of progressive display
1471 of interlaced images, depending on the mask value.
1472 The mask value describes which pixels are to be combined with
1473 the row. The pattern always repeats every 8 pixels, so just 8
1474 bits are needed. A one indicates the pixels is to be combined,
1475 a zero indicates the pixel is to be skipped. This is in addition
1476 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001477 you want all pixels to be combined, pass 0xff (255) in mask. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001478void
Guy Schalnat6d764711995-12-19 03:22:19 -06001479png_combine_row(png_structp png_ptr, png_bytep row,
Guy Schalnat0d580581995-07-20 02:43:20 -05001480 int mask)
1481{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001482 png_debug(1,"in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001483 if (mask == 0xff)
1484 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001485 png_memcpy(row, png_ptr->row_buf + 1,
Guy Schalnat0d580581995-07-20 02:43:20 -05001486 (png_size_t)((png_ptr->width *
1487 png_ptr->row_info.pixel_depth + 7) >> 3));
1488 }
1489 else
1490 {
1491 switch (png_ptr->row_info.pixel_depth)
1492 {
1493 case 1:
1494 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001495 png_bytep sp;
1496 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001497 int s_inc, s_start, s_end;
Guy Schalnat0d580581995-07-20 02:43:20 -05001498 int m;
1499 int shift;
1500 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001501
1502 sp = png_ptr->row_buf + 1;
1503 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001504 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001505#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1506 if (png_ptr->transformations & PNG_PACKSWAP)
1507 {
1508 s_start = 0;
1509 s_end = 7;
1510 s_inc = 1;
1511 }
1512 else
1513#endif
1514 {
1515 s_start = 7;
1516 s_end = 0;
1517 s_inc = -1;
1518 }
1519
1520 shift = s_start;
1521
Guy Schalnat0d580581995-07-20 02:43:20 -05001522 for (i = 0; i < png_ptr->width; i++)
1523 {
1524 if (m & mask)
1525 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001526 int value;
1527
Guy Schalnat0d580581995-07-20 02:43:20 -05001528 value = (*sp >> shift) & 0x1;
1529 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001530 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001531 }
1532
Andreas Dilger47a0c421997-05-16 02:46:07 -05001533 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001534 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001535 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001536 sp++;
1537 dp++;
1538 }
1539 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001540 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001541
1542 if (m == 1)
1543 m = 0x80;
1544 else
1545 m >>= 1;
1546 }
1547 break;
1548 }
1549 case 2:
1550 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001551 png_bytep sp;
1552 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001553 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001554 int m;
1555 int shift;
1556 png_uint_32 i;
1557 int value;
1558
1559 sp = png_ptr->row_buf + 1;
1560 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001561 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001562#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1563 if (png_ptr->transformations & PNG_PACKSWAP)
1564 {
1565 s_start = 0;
1566 s_end = 6;
1567 s_inc = 2;
1568 }
1569 else
1570#endif
1571 {
1572 s_start = 6;
1573 s_end = 0;
1574 s_inc = -2;
1575 }
1576
1577 shift = s_start;
1578
Guy Schalnat0d580581995-07-20 02:43:20 -05001579 for (i = 0; i < png_ptr->width; i++)
1580 {
1581 if (m & mask)
1582 {
1583 value = (*sp >> shift) & 0x3;
1584 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001585 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001586 }
1587
Andreas Dilger47a0c421997-05-16 02:46:07 -05001588 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001589 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001590 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001591 sp++;
1592 dp++;
1593 }
1594 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001595 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001596 if (m == 1)
1597 m = 0x80;
1598 else
1599 m >>= 1;
1600 }
1601 break;
1602 }
1603 case 4:
1604 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001605 png_bytep sp;
1606 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001607 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001608 int m;
1609 int shift;
1610 png_uint_32 i;
1611 int value;
1612
1613 sp = png_ptr->row_buf + 1;
1614 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001615 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001616#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1617 if (png_ptr->transformations & PNG_PACKSWAP)
1618 {
1619 s_start = 0;
1620 s_end = 4;
1621 s_inc = 4;
1622 }
1623 else
1624#endif
1625 {
1626 s_start = 4;
1627 s_end = 0;
1628 s_inc = -4;
1629 }
1630 shift = s_start;
1631
Guy Schalnat0d580581995-07-20 02:43:20 -05001632 for (i = 0; i < png_ptr->width; i++)
1633 {
1634 if (m & mask)
1635 {
1636 value = (*sp >> shift) & 0xf;
1637 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001638 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001639 }
1640
Andreas Dilger47a0c421997-05-16 02:46:07 -05001641 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001642 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001643 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001644 sp++;
1645 dp++;
1646 }
1647 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001648 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001649 if (m == 1)
1650 m = 0x80;
1651 else
1652 m >>= 1;
1653 }
1654 break;
1655 }
1656 default:
1657 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001658 png_bytep sp;
1659 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001660 png_size_t pixel_bytes;
1661 png_uint_32 i;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001662 png_byte m;
Guy Schalnat0d580581995-07-20 02:43:20 -05001663
1664 pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
1665
1666 sp = png_ptr->row_buf + 1;
1667 dp = row;
1668 m = 0x80;
1669 for (i = 0; i < png_ptr->width; i++)
1670 {
1671 if (m & mask)
1672 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001673 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001674 }
1675
1676 sp += pixel_bytes;
1677 dp += pixel_bytes;
1678
1679 if (m == 1)
1680 m = 0x80;
1681 else
1682 m >>= 1;
1683 }
1684 break;
1685 }
1686 }
1687 }
1688}
1689
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001690#if defined(PNG_READ_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001691void
Andreas Dilger47a0c421997-05-16 02:46:07 -05001692png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
1693 png_uint_32 transformations)
Guy Schalnat0d580581995-07-20 02:43:20 -05001694{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001695 png_debug(1,"in png_do_read_interlace\n");
1696 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05001697 {
1698 png_uint_32 final_width;
1699
1700 final_width = row_info->width * png_pass_inc[pass];
1701
1702 switch (row_info->pixel_depth)
1703 {
1704 case 1:
1705 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001706 png_bytep sp, dp;
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001707 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001708 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001709 png_byte v;
1710 png_uint_32 i;
1711 int j;
1712
1713 sp = row + (png_size_t)((row_info->width - 1) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05001714 dp = row + (png_size_t)((final_width - 1) >> 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001715#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1716 if (transformations & PNG_PACKSWAP)
1717 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001718 sshift = (int)((row_info->width + 7) & 7);
1719 dshift = (int)((final_width + 7) & 7);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001720 s_start = 7;
1721 s_end = 0;
1722 s_inc = -1;
1723 }
1724 else
1725#endif
1726 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001727 sshift = 7 - (int)((row_info->width + 7) & 7);
1728 dshift = 7 - (int)((final_width + 7) & 7);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001729 s_start = 0;
1730 s_end = 7;
1731 s_inc = 1;
1732 }
1733
Guy Schalnat0d580581995-07-20 02:43:20 -05001734 for (i = row_info->width; i; i--)
1735 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001736 v = (png_byte)((*sp >> sshift) & 0x1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001737 for (j = 0; j < png_pass_inc[pass]; j++)
1738 {
1739 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
1740 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001741 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001742 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001743 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001744 dp--;
1745 }
1746 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001747 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001748 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001749 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001750 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001751 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001752 sp--;
1753 }
1754 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001755 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001756 }
1757 break;
1758 }
1759 case 2:
1760 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001761 png_bytep sp, dp;
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001762 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001763 int s_start, s_end, s_inc;
1764 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001765
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -06001766 sp = row + (png_uint_32)((row_info->width - 1) >> 2);
1767 dp = row + (png_uint_32)((final_width - 1) >> 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001768#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1769 if (transformations & PNG_PACKSWAP)
1770 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001771 sshift = (int)(((row_info->width + 3) & 3) << 1);
1772 dshift = (int)(((final_width + 3) & 3) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001773 s_start = 6;
1774 s_end = 0;
1775 s_inc = -2;
1776 }
1777 else
1778#endif
1779 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001780 sshift = (int)((3 - ((row_info->width + 3) & 3)) << 1);
1781 dshift = (int)((3 - ((final_width + 3) & 3)) << 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001782 s_start = 0;
1783 s_end = 6;
1784 s_inc = 2;
1785 }
1786
Guy Schalnat0d580581995-07-20 02:43:20 -05001787 for (i = row_info->width; i; i--)
1788 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001789 png_byte v;
1790 int j;
1791
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001792 v = (png_byte)((*sp >> sshift) & 0x3);
Guy Schalnat0d580581995-07-20 02:43:20 -05001793 for (j = 0; j < png_pass_inc[pass]; j++)
1794 {
1795 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001796 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001797 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001798 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001799 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001800 dp--;
1801 }
1802 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001803 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001804 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001805 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001806 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001807 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001808 sp--;
1809 }
1810 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001811 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001812 }
1813 break;
1814 }
1815 case 4:
1816 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001817 png_bytep sp, dp;
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001818 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001819 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001820 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001821
1822 sp = row + (png_size_t)((row_info->width - 1) >> 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001823 dp = row + (png_size_t)((final_width - 1) >> 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001824#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1825 if (transformations & PNG_PACKSWAP)
1826 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001827 sshift = (int)(((row_info->width + 1) & 1) << 2);
1828 dshift = (int)(((final_width + 1) & 1) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001829 s_start = 4;
1830 s_end = 0;
1831 s_inc = -4;
1832 }
1833 else
1834#endif
1835 {
Glenn Randers-Pehrson983ec161998-03-07 11:24:03 -06001836 sshift = (int)((1 - ((row_info->width + 1) & 1)) << 2);
1837 dshift = (int)((1 - ((final_width + 1) & 1)) << 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001838 s_start = 0;
1839 s_end = 4;
1840 s_inc = 4;
1841 }
1842
Guy Schalnat0d580581995-07-20 02:43:20 -05001843 for (i = row_info->width; i; i--)
1844 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001845 png_byte v;
1846 int j;
1847
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001848 v = (png_byte)((*sp >> sshift) & 0xf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001849 for (j = 0; j < png_pass_inc[pass]; j++)
1850 {
1851 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06001852 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001853 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001854 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001855 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001856 dp--;
1857 }
1858 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001859 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001860 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001861 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001862 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001863 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001864 sp--;
1865 }
1866 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001867 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001868 }
1869 break;
1870 }
1871 default:
1872 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001873 png_bytep sp, dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001874 png_uint_32 i;
1875 png_size_t pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001876
1877 pixel_bytes = (row_info->pixel_depth >> 3);
1878
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001879 sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
1880 dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001881 for (i = row_info->width; i; i--)
1882 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001883 png_byte v[8];
1884 int j;
1885
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001886 png_memcpy(v, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001887 for (j = 0; j < png_pass_inc[pass]; j++)
1888 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001889 png_memcpy(dp, v, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001890 dp -= pixel_bytes;
1891 }
1892 sp -= pixel_bytes;
1893 }
1894 break;
1895 }
1896 }
1897 row_info->width = final_width;
1898 row_info->rowbytes = ((final_width *
1899 (png_uint_32)row_info->pixel_depth + 7) >> 3);
1900 }
1901}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001902#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001903
1904void
Guy Schalnate5a37791996-06-05 15:50:50 -05001905png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Guy Schalnat6d764711995-12-19 03:22:19 -06001906 png_bytep prev_row, int filter)
Guy Schalnat0d580581995-07-20 02:43:20 -05001907{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001908 png_debug(1, "in png_read_filter_row\n");
1909 png_debug2(2,"row = %d, filter = %d\n", png_ptr->row_number, filter);
1910
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001911
Guy Schalnat0d580581995-07-20 02:43:20 -05001912 switch (filter)
1913 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001914 case PNG_FILTER_VALUE_NONE:
Guy Schalnat0d580581995-07-20 02:43:20 -05001915 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001916 case PNG_FILTER_VALUE_SUB:
Guy Schalnat0d580581995-07-20 02:43:20 -05001917 {
1918 png_uint_32 i;
1919 int bpp;
Guy Schalnat6d764711995-12-19 03:22:19 -06001920 png_bytep rp;
1921 png_bytep lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001922
1923 bpp = (row_info->pixel_depth + 7) / 8;
1924 for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
1925 i < row_info->rowbytes; i++, rp++, lp++)
1926 {
1927 *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
1928 }
1929 break;
1930 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001931 case PNG_FILTER_VALUE_UP:
Guy Schalnat0d580581995-07-20 02:43:20 -05001932 {
1933 png_uint_32 i;
Guy Schalnat6d764711995-12-19 03:22:19 -06001934 png_bytep rp;
1935 png_bytep pp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001936
1937 for (i = 0, rp = row, pp = prev_row;
1938 i < row_info->rowbytes; i++, rp++, pp++)
1939 {
1940 *rp = (png_byte)(((int)(*rp) + (int)(*pp)) & 0xff);
1941 }
1942 break;
1943 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001944 case PNG_FILTER_VALUE_AVG:
Guy Schalnat0d580581995-07-20 02:43:20 -05001945 {
1946 png_uint_32 i;
1947 int bpp;
Guy Schalnat6d764711995-12-19 03:22:19 -06001948 png_bytep rp;
1949 png_bytep pp;
1950 png_bytep lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001951
1952 bpp = (row_info->pixel_depth + 7) / 8;
1953 for (i = 0, rp = row, pp = prev_row;
1954 i < (png_uint_32)bpp; i++, rp++, pp++)
1955 {
1956 *rp = (png_byte)(((int)(*rp) +
1957 ((int)(*pp) / 2)) & 0xff);
1958 }
1959 for (lp = row; i < row_info->rowbytes; i++, rp++, lp++, pp++)
1960 {
1961 *rp = (png_byte)(((int)(*rp) +
1962 (int)(*pp + *lp) / 2) & 0xff);
1963 }
1964 break;
1965 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001966 case PNG_FILTER_VALUE_PAETH:
Guy Schalnat0d580581995-07-20 02:43:20 -05001967 {
1968 int bpp;
1969 png_uint_32 i;
Guy Schalnat6d764711995-12-19 03:22:19 -06001970 png_bytep rp;
1971 png_bytep pp;
1972 png_bytep lp;
1973 png_bytep cp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001974
1975 bpp = (row_info->pixel_depth + 7) / 8;
1976 for (i = 0, rp = row, pp = prev_row,
1977 lp = row - bpp, cp = prev_row - bpp;
1978 i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
1979 {
1980 int a, b, c, pa, pb, pc, p;
1981
1982 b = *pp;
1983 if (i >= (png_uint_32)bpp)
1984 {
1985 c = *cp;
1986 a = *lp;
1987 }
1988 else
1989 {
1990 a = c = 0;
1991 }
1992 p = a + b - c;
1993 pa = abs(p - a);
1994 pb = abs(p - b);
1995 pc = abs(p - c);
1996
1997 if (pa <= pb && pa <= pc)
1998 p = a;
1999 else if (pb <= pc)
2000 p = b;
2001 else
2002 p = c;
2003
2004 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
2005 }
2006 break;
2007 }
2008 default:
Guy Schalnate5a37791996-06-05 15:50:50 -05002009 png_error(png_ptr, "Bad adaptive filter type");
Guy Schalnat0d580581995-07-20 02:43:20 -05002010 break;
2011 }
2012}
2013
2014void
Guy Schalnat6d764711995-12-19 03:22:19 -06002015png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002016{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002017 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05002018 png_ptr->row_number++;
2019 if (png_ptr->row_number < png_ptr->num_rows)
2020 return;
2021
2022 if (png_ptr->interlaced)
2023 {
2024 png_ptr->row_number = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002025 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002026 do
2027 {
2028 png_ptr->pass++;
2029 if (png_ptr->pass >= 7)
2030 break;
2031 png_ptr->iwidth = (png_ptr->width +
2032 png_pass_inc[png_ptr->pass] - 1 -
2033 png_pass_start[png_ptr->pass]) /
2034 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002035 png_ptr->irowbytes = ((png_ptr->iwidth *
2036 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
2037
Guy Schalnat0d580581995-07-20 02:43:20 -05002038 if (!(png_ptr->transformations & PNG_INTERLACE))
2039 {
2040 png_ptr->num_rows = (png_ptr->height +
2041 png_pass_yinc[png_ptr->pass] - 1 -
2042 png_pass_ystart[png_ptr->pass]) /
2043 png_pass_yinc[png_ptr->pass];
2044 if (!(png_ptr->num_rows))
2045 continue;
2046 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002047 if (png_ptr->transformations & PNG_INTERLACE)
2048 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002049 } while (png_ptr->iwidth == 0);
2050
2051 if (png_ptr->pass < 7)
2052 return;
2053 }
2054
Guy Schalnate5a37791996-06-05 15:50:50 -05002055 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002056 {
2057 char extra;
2058 int ret;
2059
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002060 png_ptr->zstream.next_out = (Byte *)&extra;
2061 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002062 for(;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05002063 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002064 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002065 {
2066 while (!png_ptr->idat_size)
2067 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002068 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002069
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002070 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002071
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002072 png_read_data(png_ptr, chunk_length, 4);
2073 png_ptr->idat_size = png_get_uint_32(chunk_length);
2074
Guy Schalnat0d580581995-07-20 02:43:20 -05002075 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002076 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
2077 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002078 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002079
2080 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002081 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2082 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002083 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002084 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2085 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2086 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002087 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002088 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002089 if (ret == Z_STREAM_END)
2090 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002091 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002092 png_ptr->idat_size)
Guy Schalnat6d764711995-12-19 03:22:19 -06002093 png_error(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002094 png_ptr->mode |= PNG_AFTER_IDAT;
2095 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002096 break;
2097 }
2098 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002099 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05002100 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05002101
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002102 if (!(png_ptr->zstream.avail_out))
Guy Schalnat6d764711995-12-19 03:22:19 -06002103 png_error(png_ptr, "Extra compressed data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002104
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06002105 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002106 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002107 }
2108
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002109 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Guy Schalnat6d764711995-12-19 03:22:19 -06002110 png_error(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002111
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002112 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05002113
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002114 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002115}
2116
2117void
Guy Schalnat6d764711995-12-19 03:22:19 -06002118png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002119{
2120 int max_pixel_depth;
2121 png_uint_32 rowbytes;
2122
Andreas Dilger47a0c421997-05-16 02:46:07 -05002123 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002124 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002125 png_init_read_transformations(png_ptr);
2126 if (png_ptr->interlaced)
2127 {
2128 if (!(png_ptr->transformations & PNG_INTERLACE))
2129 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
2130 png_pass_ystart[0]) / png_pass_yinc[0];
2131 else
2132 png_ptr->num_rows = png_ptr->height;
2133
2134 png_ptr->iwidth = (png_ptr->width +
2135 png_pass_inc[png_ptr->pass] - 1 -
2136 png_pass_start[png_ptr->pass]) /
2137 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002138
2139 rowbytes = ((png_ptr->iwidth *
2140 (png_uint_32)png_ptr->pixel_depth + 7) >> 3) +1;
2141 png_ptr->irowbytes = (png_size_t)rowbytes;
2142 if((png_uint_32)png_ptr->irowbytes != rowbytes)
2143 png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05002144 }
2145 else
2146 {
2147 png_ptr->num_rows = png_ptr->height;
2148 png_ptr->iwidth = png_ptr->width;
2149 png_ptr->irowbytes = png_ptr->rowbytes + 1;
2150 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002151 max_pixel_depth = png_ptr->pixel_depth;
2152
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002153#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002154 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002155 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002156#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002157
Guy Schalnate5a37791996-06-05 15:50:50 -05002158#if defined(PNG_READ_EXPAND_SUPPORTED)
2159 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002160 {
2161 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2162 {
2163 if (png_ptr->num_trans)
2164 max_pixel_depth = 32;
2165 else
2166 max_pixel_depth = 24;
2167 }
2168 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
2169 {
2170 if (max_pixel_depth < 8)
2171 max_pixel_depth = 8;
2172 if (png_ptr->num_trans)
2173 max_pixel_depth *= 2;
2174 }
2175 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2176 {
2177 if (png_ptr->num_trans)
2178 {
2179 max_pixel_depth *= 4;
2180 max_pixel_depth /= 3;
2181 }
2182 }
2183 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002184#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002185
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002186#if defined(PNG_READ_FILLER_SUPPORTED)
2187 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05002188 {
2189 if (max_pixel_depth < 32)
2190 max_pixel_depth = 32;
2191 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002192#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002193
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002194#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002195 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
2196 {
2197 if ((png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
2198 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2199 {
2200 if (max_pixel_depth <= 16)
2201 max_pixel_depth = 32;
2202 else if (max_pixel_depth <= 32)
2203 max_pixel_depth = 64;
2204 }
2205 else
2206 {
2207 if (max_pixel_depth <= 8)
2208 max_pixel_depth = 24;
2209 else if (max_pixel_depth <= 16)
2210 max_pixel_depth = 48;
2211 }
2212 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002213#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002214
2215 /* align the width on the next larger 8 pixels. Mainly used
2216 for interlacing */
2217 rowbytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
2218 /* calculate the maximum bytes needed, adding a byte and a pixel
2219 for safety sake */
2220 rowbytes = ((rowbytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
2221 1 + ((max_pixel_depth + 7) >> 3);
2222#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002223 if (rowbytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002224 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002225#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002226 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002227
2228#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002229 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002230 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002231#endif
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06002232 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
2233 png_ptr->rowbytes + 1));
Guy Schalnat0d580581995-07-20 02:43:20 -05002234
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002235 png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002236
2237 png_debug1(3, "width = %d,\n", png_ptr->width);
2238 png_debug1(3, "height = %d,\n", png_ptr->height);
2239 png_debug1(3, "iwidth = %d,\n", png_ptr->iwidth);
2240 png_debug1(3, "num_rows = %d\n", png_ptr->num_rows);
2241 png_debug1(3, "rowbytes = %d,\n", png_ptr->rowbytes);
2242 png_debug1(3, "irowbytes = %d,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002243
Guy Schalnate5a37791996-06-05 15:50:50 -05002244 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002245}