blob: 73e1a53a5dec5b2719be1c1bcee0670863d3f113 [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-Pehrson46f61e21998-01-30 21:45:12 -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-Pehrson46f61e21998-01-30 21:45:12 -06009 * January 30, 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
30 return i;
31}
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
47 return i;
48}
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
60 return i;
61}
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 }
103 return 1;
104 }
105
106 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);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500135 return (crc != png_ptr->crc);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500136 }
137 else
138 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 *
229 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
261#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
262 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
263 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600264 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500265 return;
266 }
267#endif
268
Guy Schalnat0d580581995-07-20 02:43:20 -0500269 if (length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500270 {
271 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
272 {
273 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600274 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500275 return;
276 }
277 else
278 {
279 png_error(png_ptr, "Invalid palette chunk");
280 }
281 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500282
283 num = (int)length / 3;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600284 palette = (png_colorp)png_zalloc(png_ptr, (uInt)num, sizeof (png_color));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600285 png_ptr->flags |= PNG_FLAG_FREE_PALETTE;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600286 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500287 {
288 png_byte buf[3];
289
290 png_crc_read(png_ptr, buf, 3);
291 /* don't depend upon png_color being any order */
292 palette[i].red = buf[0];
293 palette[i].green = buf[1];
294 palette[i].blue = buf[2];
295 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600296
297 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
298 whatever the normal CRC configuration tells us. However, if we
299 have an RGB image, the PLTE can be considered ancillary, so
300 we will act as though it is. */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600301#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600302 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600303#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600304 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500305 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600306 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600307#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600308 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
309 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600310 /* If we don't want to use the data from an ancillary chunk,
311 we have two options: an error abort, or a warning and we
312 ignore the data in this chunk (which should be OK, since
313 it's considered ancillary for a RGB or RGBA image). */
314 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
315 {
316 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
317 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600318 png_chunk_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600319 }
320 else
321 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600322 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500323 png_ptr->flags &= ~PNG_FLAG_FREE_PALETTE;
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600324 png_zfree(png_ptr, palette);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600325 return;
326 }
327 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500328 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600329 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
330 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600331 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600332 }
333 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600334#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500335 png_ptr->palette = palette;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600336 png_ptr->num_palette = (png_uint_16)num;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500337 png_set_PLTE(png_ptr, info_ptr, palette, num);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600338}
Guy Schalnate5a37791996-06-05 15:50:50 -0500339
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600340void
341png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
342{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500343 png_debug(1, "in png_handle_IEND\n");
344
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600345 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
346 {
347 png_error(png_ptr, "No image in file");
348 }
349
350 png_ptr->mode |= PNG_AFTER_IDAT | PNG_HAVE_IEND;
351
352 if (length != 0)
353 {
354 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600355 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500356 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500357}
358
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500359#if defined(PNG_READ_gAMA_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500360void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600361png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500362{
363 png_uint_32 igamma;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500364 float file_gamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500365 png_byte buf[4];
366
Andreas Dilger47a0c421997-05-16 02:46:07 -0500367 png_debug(1, "in png_handle_gAMA\n");
368
Guy Schalnate5a37791996-06-05 15:50:50 -0500369 if (!(png_ptr->mode & PNG_HAVE_IHDR))
370 png_error(png_ptr, "Missing IHDR before gAMA");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600371 else if (png_ptr->mode & PNG_HAVE_IDAT)
372 {
373 png_warning(png_ptr, "Invalid gAMA after IDAT");
374 png_crc_finish(png_ptr, length);
375 return;
376 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500377 else if (png_ptr->mode & PNG_HAVE_PLTE)
378 /* Should be an error, but we can cope with it */
379 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600380
381 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_gAMA
382#if defined(PNG_READ_sRGB_SUPPORTED)
383 && !(info_ptr->valid & PNG_INFO_sRGB)
384#endif
385 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600386 {
387 png_warning(png_ptr, "Duplicate gAMA chunk");
388 png_crc_finish(png_ptr, length);
389 return;
390 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500391
Guy Schalnat0d580581995-07-20 02:43:20 -0500392 if (length != 4)
393 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600394 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600395 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500396 return;
397 }
398
399 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600400 if (png_crc_finish(png_ptr, 0))
401 return;
402
Guy Schalnat0d580581995-07-20 02:43:20 -0500403 igamma = png_get_uint_32(buf);
404 /* check for zero gamma */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500405 if (igamma == 0)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600406 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500407
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600408#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600409 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600410 if(igamma != (png_uint_32)45000L)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600411 {
412 png_warning(png_ptr,
413 "Ignoring incorrect gAMA value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600414#ifndef PNG_NO_STDIO
415 fprintf(stderr, "igamma = %lu\n", igamma);
416#endif
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600417 return;
418 }
419#endif /* PNG_READ_sRGB_SUPPORTED */
420
Andreas Dilger47a0c421997-05-16 02:46:07 -0500421 file_gamma = (float)igamma / (float)100000.0;
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600422#ifdef PNG_READ_GAMMA_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500423 png_ptr->gamma = file_gamma;
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600424#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -0500425 png_set_gAMA(png_ptr, info_ptr, file_gamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500426}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500427#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500428
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500429#if defined(PNG_READ_sBIT_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500430void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600431png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500432{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500433 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600434 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600435
Andreas Dilger47a0c421997-05-16 02:46:07 -0500436 png_debug(1, "in png_handle_sBIT\n");
437
Guy Schalnat69b14481996-01-10 02:56:49 -0600438 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500439
Guy Schalnate5a37791996-06-05 15:50:50 -0500440 if (!(png_ptr->mode & PNG_HAVE_IHDR))
441 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600442 else if (png_ptr->mode & PNG_HAVE_IDAT)
443 {
444 png_warning(png_ptr, "Invalid sBIT after IDAT");
445 png_crc_finish(png_ptr, length);
446 return;
447 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500448 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600449 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500450 /* Should be an error, but we can cope with it */
451 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600452 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500453 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sBIT)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600454 {
455 png_warning(png_ptr, "Duplicate sBIT chunk");
456 png_crc_finish(png_ptr, length);
457 return;
458 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500459
Guy Schalnat0d580581995-07-20 02:43:20 -0500460 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600461 truelen = 3;
Guy Schalnat0d580581995-07-20 02:43:20 -0500462 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500463 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500464
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600465 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500466 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600467 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600468 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600469 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500470 }
471
Andreas Dilger47a0c421997-05-16 02:46:07 -0500472 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600473 if (png_crc_finish(png_ptr, 0))
474 return;
475
Guy Schalnat0d580581995-07-20 02:43:20 -0500476 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
477 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600478 png_ptr->sig_bit.red = buf[0];
479 png_ptr->sig_bit.green = buf[1];
480 png_ptr->sig_bit.blue = buf[2];
481 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500482 }
483 else
484 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600485 png_ptr->sig_bit.gray = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600486 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500487 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500488 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500489}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500490#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500491
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500492#if defined(PNG_READ_cHRM_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500493void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600494png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500495{
496 png_byte buf[4];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600497 png_uint_32 val;
Guy Schalnat0d580581995-07-20 02:43:20 -0500498 float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
499
Andreas Dilger47a0c421997-05-16 02:46:07 -0500500 png_debug(1, "in png_handle_cHRM\n");
501
Guy Schalnate5a37791996-06-05 15:50:50 -0500502 if (!(png_ptr->mode & PNG_HAVE_IHDR))
503 png_error(png_ptr, "Missing IHDR before sBIT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600504 else if (png_ptr->mode & PNG_HAVE_IDAT)
505 {
506 png_warning(png_ptr, "Invalid cHRM after IDAT");
507 png_crc_finish(png_ptr, length);
508 return;
509 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500510 else if (png_ptr->mode & PNG_HAVE_PLTE)
511 /* Should be an error, but we can cope with it */
512 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600513
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600514 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_cHRM
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600515#if defined(PNG_READ_sRGB_SUPPORTED)
516 && !(info_ptr->valid & PNG_INFO_sRGB)
517#endif
518 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600519 {
520 png_warning(png_ptr, "Duplicate cHRM chunk");
521 png_crc_finish(png_ptr, length);
522 return;
523 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500524
Guy Schalnat0d580581995-07-20 02:43:20 -0500525 if (length != 32)
526 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600527 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600528 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600529 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500530 }
531
532 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600533 val = png_get_uint_32(buf);
534 white_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500535
536 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600537 val = png_get_uint_32(buf);
538 white_y = (float)val / (float)100000.0;
539
540 if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
541 white_x + white_y > 1.0)
542 {
543 png_warning(png_ptr, "Invalid cHRM white point");
544 png_crc_finish(png_ptr, 24);
545 return;
546 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500547
548 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600549 val = png_get_uint_32(buf);
550 red_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500551
552 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600553 val = png_get_uint_32(buf);
554 red_y = (float)val / (float)100000.0;
555
556 if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 ||
557 red_x + red_y > 1.0)
558 {
559 png_warning(png_ptr, "Invalid cHRM red point");
560 png_crc_finish(png_ptr, 16);
561 return;
562 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500563
564 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600565 val = png_get_uint_32(buf);
566 green_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500567
568 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600569 val = png_get_uint_32(buf);
570 green_y = (float)val / (float)100000.0;
571
572 if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 ||
573 green_x + green_y > 1.0)
574 {
575 png_warning(png_ptr, "Invalid cHRM green point");
576 png_crc_finish(png_ptr, 8);
577 return;
578 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500579
580 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600581 val = png_get_uint_32(buf);
582 blue_x = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500583
584 png_crc_read(png_ptr, buf, 4);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600585 val = png_get_uint_32(buf);
586 blue_y = (float)val / (float)100000.0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500587
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600588 if (blue_x < (float)0 || blue_x > (float)0.8 || blue_y < (float)0 ||
589 blue_y > (float)0.8 || blue_x + blue_y > (float)1.0)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600590 {
591 png_warning(png_ptr, "Invalid cHRM blue point");
592 png_crc_finish(png_ptr, 0);
593 return;
594 }
595
596 if (png_crc_finish(png_ptr, 0))
597 return;
598
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600599#if defined(PNG_READ_sRGB_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600600 if (info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600601 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600602 if (fabs(white_x - (float).3127) > (float).001 ||
603 fabs(white_y - (float).3290) > (float).001 ||
604 fabs( red_x - (float).6400) > (float).001 ||
605 fabs( red_y - (float).3300) > (float).001 ||
606 fabs(green_x - (float).3000) > (float).001 ||
607 fabs(green_y - (float).6000) > (float).001 ||
608 fabs( blue_x - (float).1500) > (float).001 ||
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600609 fabs( blue_y - (float).0600) > (float).001)
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600610 {
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600611
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600612 png_warning(png_ptr,
613 "Ignoring incorrect cHRM value when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600614#ifndef PNG_NO_STDIO
615 fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
616 white_x, white_y, red_x, red_y);
617 fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
618 green_x, green_y, blue_x, blue_y);
619#endif
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600620 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600621 return;
622 }
623#endif /* PNG_READ_sRGB_SUPPORTED */
624
Andreas Dilger47a0c421997-05-16 02:46:07 -0500625 png_set_cHRM(png_ptr, info_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600626 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
Guy Schalnat0d580581995-07-20 02:43:20 -0500627}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500628#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500629
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600630#if defined(PNG_READ_sRGB_SUPPORTED)
631void
632png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
633{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600634 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600635 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600636
637 png_debug(1, "in png_handle_sRGB\n");
638
639 if (!(png_ptr->mode & PNG_HAVE_IHDR))
640 png_error(png_ptr, "Missing IHDR before sRGB");
641 else if (png_ptr->mode & PNG_HAVE_IDAT)
642 {
643 png_warning(png_ptr, "Invalid sRGB after IDAT");
644 png_crc_finish(png_ptr, length);
645 return;
646 }
647 else if (png_ptr->mode & PNG_HAVE_PLTE)
648 /* Should be an error, but we can cope with it */
649 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600650
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600651 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_sRGB)
652 {
653 png_warning(png_ptr, "Duplicate sRGB chunk");
654 png_crc_finish(png_ptr, length);
655 return;
656 }
657
658 if (length != 1)
659 {
660 png_warning(png_ptr, "Incorrect sRGB chunk length");
661 png_crc_finish(png_ptr, length);
662 return;
663 }
664
665 png_crc_read(png_ptr, buf, 1);
666 if (png_crc_finish(png_ptr, 0))
667 return;
668
669 intent = buf[0];
670 /* check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600671 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600672 {
673 png_warning(png_ptr, "Unknown sRGB intent");
674 return;
675 }
676
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600677#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600678 if ((info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600679 if((png_uint_32)(png_ptr->gamma*(float)100000.+.5) != (png_uint_32)45000L)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600680 {
681 png_warning(png_ptr,
682 "Ignoring incorrect gAMA value when sRGB is also present");
683#ifndef PNG_NO_STDIO
684 fprintf(stderr,"gamma=%f\n",png_ptr->gamma);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600685#endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600686 }
687#endif /* PNG_READ_gAMA_SUPPORTED */
688
689#ifdef PNG_READ_cHRM_SUPPORTED
690 if (info_ptr->valid & PNG_INFO_cHRM)
691 if (fabs(info_ptr->x_white - (float).3127) > (float).001 ||
692 fabs(info_ptr->y_white - (float).3290) > (float).001 ||
693 fabs( info_ptr->x_red - (float).6400) > (float).001 ||
694 fabs( info_ptr->y_red - (float).3300) > (float).001 ||
695 fabs(info_ptr->x_green - (float).3000) > (float).001 ||
696 fabs(info_ptr->y_green - (float).6000) > (float).001 ||
697 fabs( info_ptr->x_blue - (float).1500) > (float).001 ||
698 fabs( info_ptr->y_blue - (float).0600) > (float).001)
699 {
700 png_warning(png_ptr,
701 "Ignoring incorrect cHRM value when sRGB is also present");
702 }
703#endif /* PNG_READ_cHRM_SUPPORTED */
704
705 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
706}
707#endif /* PNG_READ_sRGB_SUPPORTED */
708
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500709#if defined(PNG_READ_tRNS_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500710void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600711png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500712{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500713 png_debug(1, "in png_handle_tRNS\n");
714
Guy Schalnate5a37791996-06-05 15:50:50 -0500715 if (!(png_ptr->mode & PNG_HAVE_IHDR))
716 png_error(png_ptr, "Missing IHDR before tRNS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600717 else if (png_ptr->mode & PNG_HAVE_IDAT)
718 {
719 png_warning(png_ptr, "Invalid tRNS after IDAT");
720 png_crc_finish(png_ptr, length);
721 return;
722 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500723 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tRNS)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600724 {
725 png_warning(png_ptr, "Duplcate tRNS chunk");
726 png_crc_finish(png_ptr, length);
727 return;
728 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500729
Guy Schalnat0d580581995-07-20 02:43:20 -0500730 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
731 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500732 if (!(png_ptr->mode & PNG_HAVE_PLTE))
733 {
734 /* Should be an error, but we can cope with it */
735 png_warning(png_ptr, "Missing PLTE before tRNS");
736 }
737 else if (length > png_ptr->num_palette)
Guy Schalnat0d580581995-07-20 02:43:20 -0500738 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600739 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600740 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500741 return;
742 }
743
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600744 png_ptr->trans = (png_bytep)png_malloc(png_ptr, length);
745 png_ptr->flags |= PNG_FLAG_FREE_TRANS;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500746 png_crc_read(png_ptr, png_ptr->trans, (png_size_t)length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600747 png_ptr->num_trans = (png_uint_16)length;
Guy Schalnat0d580581995-07-20 02:43:20 -0500748 }
749 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
750 {
751 png_byte buf[6];
752
753 if (length != 6)
754 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600755 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600756 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500757 return;
758 }
759
Andreas Dilger47a0c421997-05-16 02:46:07 -0500760 png_crc_read(png_ptr, buf, (png_size_t)length);
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600761 png_ptr->num_trans = 1;
Guy Schalnat0d580581995-07-20 02:43:20 -0500762 png_ptr->trans_values.red = png_get_uint_16(buf);
763 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
764 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
765 }
766 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
767 {
768 png_byte buf[6];
769
770 if (length != 2)
771 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600772 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600773 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600774 return;
775 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500776
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600777 png_crc_read(png_ptr, buf, 2);
778 png_ptr->num_trans = 1;
779 png_ptr->trans_values.gray = png_get_uint_16(buf);
780 }
781 else
Guy Schalnate5a37791996-06-05 15:50:50 -0500782 {
783 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600784 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500785 return;
786 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500787
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600788 if (png_crc_finish(png_ptr, 0))
789 return;
790
Andreas Dilger47a0c421997-05-16 02:46:07 -0500791 png_set_tRNS(png_ptr, info_ptr, png_ptr->trans, png_ptr->num_trans,
Guy Schalnat0d580581995-07-20 02:43:20 -0500792 &(png_ptr->trans_values));
793}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500794#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500795
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500796#if defined(PNG_READ_bKGD_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500797void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600798png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500799{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500800 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -0500801 png_byte buf[6];
802
Andreas Dilger47a0c421997-05-16 02:46:07 -0500803 png_debug(1, "in png_handle_bKGD\n");
804
Guy Schalnate5a37791996-06-05 15:50:50 -0500805 if (!(png_ptr->mode & PNG_HAVE_IHDR))
806 png_error(png_ptr, "Missing IHDR before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600807 else if (png_ptr->mode & PNG_HAVE_IDAT)
808 {
809 png_warning(png_ptr, "Invalid bKGD after IDAT");
810 png_crc_finish(png_ptr, length);
811 return;
812 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500813 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
814 !(png_ptr->mode & PNG_HAVE_PLTE))
815 {
816 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600817 png_crc_finish(png_ptr, length);
818 return;
819 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500820 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_bKGD)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600821 {
822 png_warning(png_ptr, "Duplicate bKGD chunk");
823 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500824 return;
825 }
826
Guy Schalnat0d580581995-07-20 02:43:20 -0500827 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
828 truelen = 1;
829 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
830 truelen = 6;
831 else
832 truelen = 2;
833
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600834 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -0500835 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600836 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600837 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500838 return;
839 }
840
Andreas Dilger47a0c421997-05-16 02:46:07 -0500841 png_crc_read(png_ptr, buf, truelen);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600842 if (png_crc_finish(png_ptr, 0))
843 return;
844
Guy Schalnate5a37791996-06-05 15:50:50 -0500845 /* We convert the index value into RGB components so that we can allow
846 * arbitrary RGB values for background when we have transparency, and
847 * so it is easy to determine the RGB values of the background color
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600848 * from the info_ptr struct. */
Guy Schalnat0d580581995-07-20 02:43:20 -0500849 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -0500850 {
Guy Schalnat0d580581995-07-20 02:43:20 -0500851 png_ptr->background.index = buf[0];
Guy Schalnate5a37791996-06-05 15:50:50 -0500852 png_ptr->background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
853 png_ptr->background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
854 png_ptr->background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
855 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500856 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -0500857 {
858 png_ptr->background.red =
859 png_ptr->background.green =
860 png_ptr->background.blue =
Guy Schalnat0d580581995-07-20 02:43:20 -0500861 png_ptr->background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -0500862 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500863 else
864 {
865 png_ptr->background.red = png_get_uint_16(buf);
866 png_ptr->background.green = png_get_uint_16(buf + 2);
867 png_ptr->background.blue = png_get_uint_16(buf + 4);
868 }
869
Andreas Dilger47a0c421997-05-16 02:46:07 -0500870 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
Guy Schalnat0d580581995-07-20 02:43:20 -0500871}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500872#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500873
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500874#if defined(PNG_READ_hIST_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500875void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600876png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500877{
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600878 int num, i;
Guy Schalnat0d580581995-07-20 02:43:20 -0500879
Andreas Dilger47a0c421997-05-16 02:46:07 -0500880 png_debug(1, "in png_handle_hIST\n");
881
Guy Schalnate5a37791996-06-05 15:50:50 -0500882 if (!(png_ptr->mode & PNG_HAVE_IHDR))
883 png_error(png_ptr, "Missing IHDR before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600884 else if (png_ptr->mode & PNG_HAVE_IDAT)
885 {
886 png_warning(png_ptr, "Invalid hIST after IDAT");
887 png_crc_finish(png_ptr, length);
888 return;
889 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500890 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
891 {
892 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600893 png_crc_finish(png_ptr, length);
894 return;
895 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500896 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_hIST)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600897 {
898 png_warning(png_ptr, "Duplicate hIST chunk");
899 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500900 return;
901 }
902
Andreas Dilger47a0c421997-05-16 02:46:07 -0500903 if (length != (png_uint_32)(2 * png_ptr->num_palette))
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600904 {
905 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600906 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600907 return;
908 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500909
910 num = (int)length / 2;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600911 png_ptr->hist = (png_uint_16p)png_malloc(png_ptr,
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600912 num * sizeof (png_uint_16));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600913 png_ptr->flags |= PNG_FLAG_FREE_HIST;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600914 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500915 {
916 png_byte buf[2];
917
918 png_crc_read(png_ptr, buf, 2);
919 png_ptr->hist[i] = png_get_uint_16(buf);
920 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600921
922 if (png_crc_finish(png_ptr, 0))
923 return;
924
Andreas Dilger47a0c421997-05-16 02:46:07 -0500925 png_set_hIST(png_ptr, info_ptr, png_ptr->hist);
Guy Schalnat0d580581995-07-20 02:43:20 -0500926}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500927#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500928
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500929#if defined(PNG_READ_pHYs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500930void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600931png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500932{
933 png_byte buf[9];
934 png_uint_32 res_x, res_y;
935 int unit_type;
936
Andreas Dilger47a0c421997-05-16 02:46:07 -0500937 png_debug(1, "in png_handle_pHYs\n");
938
Guy Schalnate5a37791996-06-05 15:50:50 -0500939 if (!(png_ptr->mode & PNG_HAVE_IHDR))
940 png_error(png_ptr, "Missing IHDR before pHYS");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600941 else if (png_ptr->mode & PNG_HAVE_IDAT)
942 {
943 png_warning(png_ptr, "Invalid pHYS after IDAT");
944 png_crc_finish(png_ptr, length);
945 return;
946 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500947 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pHYs)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600948 {
949 png_warning(png_ptr, "Duplicate pHYS chunk");
950 png_crc_finish(png_ptr, length);
951 return;
952 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500953
Guy Schalnat0d580581995-07-20 02:43:20 -0500954 if (length != 9)
955 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600956 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600957 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600959 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500960
961 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600962 if (png_crc_finish(png_ptr, 0))
963 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500964
965 res_x = png_get_uint_32(buf);
966 res_y = png_get_uint_32(buf + 4);
967 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -0500968 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500969}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500970#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500971
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500972#if defined(PNG_READ_oFFs_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -0500973void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600974png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500975{
976 png_byte buf[9];
977 png_uint_32 offset_x, offset_y;
978 int unit_type;
979
Andreas Dilger47a0c421997-05-16 02:46:07 -0500980 png_debug(1, "in png_handle_oFFs\n");
981
Guy Schalnate5a37791996-06-05 15:50:50 -0500982 if (!(png_ptr->mode & PNG_HAVE_IHDR))
983 png_error(png_ptr, "Missing IHDR before oFFs");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600984 else if (png_ptr->mode & PNG_HAVE_IDAT)
985 {
986 png_warning(png_ptr, "Invalid oFFs after IDAT");
987 png_crc_finish(png_ptr, length);
988 return;
989 }
Andreas Dilger47a0c421997-05-16 02:46:07 -0500990 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_oFFs)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600991 {
992 png_warning(png_ptr, "Duplicate oFFs chunk");
993 png_crc_finish(png_ptr, length);
994 return;
995 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500996
Guy Schalnat0d580581995-07-20 02:43:20 -0500997 if (length != 9)
998 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600999 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001000 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001001 return;
1002 }
1003
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001004 png_crc_read(png_ptr, buf, 9);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001005 if (png_crc_finish(png_ptr, 0))
1006 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001007
1008 offset_x = png_get_uint_32(buf);
1009 offset_y = png_get_uint_32(buf + 4);
1010 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001011 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1012}
1013#endif
1014
1015#if defined(PNG_READ_pCAL_SUPPORTED)
1016/* read the pCAL chunk (png-scivis-19970203) */
1017void
1018png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1019{
1020 png_charp purpose;
1021 png_int_32 X0, X1;
1022 png_byte type, nparams;
1023 png_charp buf, units, endptr;
1024 png_charpp params;
1025 int i;
1026
1027 png_debug(1, "in png_handle_pCAL\n");
1028
1029 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1030 png_error(png_ptr, "Missing IHDR before pCAL");
1031 else if (png_ptr->mode & PNG_HAVE_IDAT)
1032 {
1033 png_warning(png_ptr, "Invalid pCAL after IDAT");
1034 png_crc_finish(png_ptr, length);
1035 return;
1036 }
1037 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_pCAL)
1038 {
1039 png_warning(png_ptr, "Duplicate pCAL chunk");
1040 png_crc_finish(png_ptr, length);
1041 return;
1042 }
1043
1044 png_debug1(2, "Allocating and reading pCAL chunk data (%d bytes)\n",
1045 length + 1);
1046 purpose = (png_charp)png_malloc(png_ptr, length + 1);
1047 png_crc_read(png_ptr, (png_bytep)purpose, (png_size_t)length);
1048
1049 if (png_crc_finish(png_ptr, 0))
1050 {
1051 png_free(png_ptr, purpose);
1052 return;
1053 }
1054
1055 purpose[length] = '\0'; /* null terminate the last string */
1056
1057 png_debug(3, "Finding end of pCAL purpose string\n");
1058 for (buf = purpose; *buf != '\0'; buf++)
1059 /* empty loop */;
1060
1061 endptr = purpose + length;
1062
1063 /* We need to have at least 12 bytes after the purpose string
1064 in order to get the parameter information. */
1065 if (endptr <= buf + 12)
1066 {
1067 png_warning(png_ptr, "Invalid pCAL data");
1068 png_free(png_ptr, purpose);
1069 return;
1070 }
1071
1072 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
1073 X0 = png_get_int_32((png_bytep)buf+1);
1074 X1 = png_get_int_32((png_bytep)buf+5);
1075 type = buf[9];
1076 nparams = buf[10];
1077 units = buf + 11;
1078
1079 png_debug(3, "Checking pCAL equation type and number of parameters\n");
1080 /* Check that we have the right number of parameters for known
1081 equation types. */
1082 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1083 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1084 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1085 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1086 {
1087 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
1088 png_free(png_ptr, purpose);
1089 return;
1090 }
1091 else if (type >= PNG_EQUATION_LAST)
1092 {
1093 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1094 }
1095
1096 /* Empty loop to move past the units string. */
1097 for (buf = units; *buf != '\0'; buf++);
1098
1099 png_debug(3, "Allocating pCAL parameters array\n");
1100 params = (png_charpp)png_malloc(png_ptr, nparams*sizeof(png_charp)) ;
1101
1102 /* Get pointers to the start of each parameter string. */
1103 for (i = 0; i < nparams; i++)
1104 {
1105 buf++; /* Skip the null string terminator from previous parameter. */
1106
1107 png_debug1(3, "Reading pCAL parameter %d\n", i);
1108 /* Empty loop to move past each paramter string */
1109 for (params[i] = buf; *buf != '\0' && buf <= endptr; buf++);
1110
1111 /* Make sure we haven't run out of data yet */
1112 if (buf > endptr)
1113 {
1114 png_warning(png_ptr, "Invalid pCAL data");
1115 png_free(png_ptr, purpose);
1116 png_free(png_ptr, params);
1117 return;
1118 }
1119 }
1120
1121 png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
1122 units, params);
1123
1124 png_free(png_ptr, purpose);
1125 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001126}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001127#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001128
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001129#if defined(PNG_READ_tIME_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001130void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001131png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001132{
1133 png_byte buf[7];
1134 png_time mod_time;
1135
Andreas Dilger47a0c421997-05-16 02:46:07 -05001136 png_debug(1, "in png_handle_tIME\n");
1137
Guy Schalnate5a37791996-06-05 15:50:50 -05001138 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001139 png_error(png_ptr, "Out of place tIME chunk");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001140 else if (info_ptr != NULL && info_ptr->valid & PNG_INFO_tIME)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001141 {
1142 png_warning(png_ptr, "Duplicate tIME chunk");
1143 png_crc_finish(png_ptr, length);
1144 return;
1145 }
1146
1147 if (png_ptr->mode & PNG_HAVE_IDAT)
1148 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05001149
Guy Schalnat0d580581995-07-20 02:43:20 -05001150 if (length != 7)
1151 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001152 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001153 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001154 return;
1155 }
1156
1157 png_crc_read(png_ptr, buf, 7);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001158 if (png_crc_finish(png_ptr, 0))
1159 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001160
1161 mod_time.second = buf[6];
1162 mod_time.minute = buf[5];
1163 mod_time.hour = buf[4];
1164 mod_time.day = buf[3];
1165 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001166 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001167
Andreas Dilger47a0c421997-05-16 02:46:07 -05001168 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05001169}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001170#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001171
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001172#if defined(PNG_READ_tEXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001173/* Note: this does not properly handle chunks that are > 64K under DOS */
Guy Schalnat0d580581995-07-20 02:43:20 -05001174void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001175png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001176{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001177 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001178 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06001179 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001180 png_uint_32 skip = 0;
1181
1182 png_debug(1, "in png_handle_tEXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001183
Guy Schalnate5a37791996-06-05 15:50:50 -05001184 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1185 png_error(png_ptr, "Missing IHDR before tEXt");
1186
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001187 if (png_ptr->mode & PNG_HAVE_IDAT)
1188 png_ptr->mode |= PNG_AFTER_IDAT;
1189
Andreas Dilger47a0c421997-05-16 02:46:07 -05001190#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001191 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001192 {
1193 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001194 skip = length - (png_uint_32)65535L;
1195 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001196 }
1197#endif
1198
1199 key = (png_charp)png_malloc(png_ptr, length + 1);
1200 png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
1201
1202 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001203 {
1204 png_free(png_ptr, key);
1205 return;
1206 }
1207
Andreas Dilger47a0c421997-05-16 02:46:07 -05001208 key[length] = '\0';
Guy Schalnat0d580581995-07-20 02:43:20 -05001209
1210 for (text = key; *text; text++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001211 /* empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05001212
1213 if (text != key + (png_size_t)length)
1214 text++;
1215
Andreas Dilger47a0c421997-05-16 02:46:07 -05001216 text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
1217 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
1218 text_ptr->key = key;
1219 text_ptr->text = text;
1220
1221 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1222
1223 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001224}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001225#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001226
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001227#if defined(PNG_READ_zTXt_SUPPORTED)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001228/* note: this does not correctly handle chunks that are > 64K under DOS */
Guy Schalnat0d580581995-07-20 02:43:20 -05001229void
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001230png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001231{
Guy Schalnate5a37791996-06-05 15:50:50 -05001232 static char msg[] = "Error decoding zTXt chunk";
Andreas Dilger47a0c421997-05-16 02:46:07 -05001233 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06001234 png_charp key;
1235 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001236 int comp_type = PNG_TEXT_COMPRESSION_NONE;
1237
1238 png_debug(1, "in png_handle_zTXt\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001239
Guy Schalnate5a37791996-06-05 15:50:50 -05001240 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1241 png_error(png_ptr, "Missing IHDR before zTXt");
1242
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001243 if (png_ptr->mode & PNG_HAVE_IDAT)
1244 png_ptr->mode |= PNG_AFTER_IDAT;
1245
Andreas Dilger47a0c421997-05-16 02:46:07 -05001246#ifdef PNG_MAX_MALLOC_64K
1247 /* We will no doubt have problems with chunks even half this size, but
1248 there is no hard and fast rule to tell us where to stop. */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001249 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001250 {
1251 png_warning(png_ptr,"zTXt chunk too large to fit in memory");
1252 png_crc_finish(png_ptr, length);
1253 return;
1254 }
1255#endif
1256
1257 key = (png_charp)png_malloc(png_ptr, length + 1);
1258 png_crc_read(png_ptr, (png_bytep)key, (png_size_t)length);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001259 if (png_crc_finish(png_ptr, 0))
1260 {
1261 png_free(png_ptr, key);
1262 return;
1263 }
1264
Andreas Dilger47a0c421997-05-16 02:46:07 -05001265 key[length] = '\0';
Guy Schalnat0d580581995-07-20 02:43:20 -05001266
1267 for (text = key; *text; text++)
1268 /* empty loop */ ;
1269
Andreas Dilger47a0c421997-05-16 02:46:07 -05001270 /* zTXt must have some text after the keyword */
Guy Schalnat0d580581995-07-20 02:43:20 -05001271 if (text == key + (png_size_t)length)
1272 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001273 png_warning(png_ptr, "Zero length zTXt chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05001274 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001275 else if ((comp_type = *(++text)) == PNG_TEXT_COMPRESSION_zTXt)
Guy Schalnat0d580581995-07-20 02:43:20 -05001276 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001277 png_size_t text_size, key_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001278 text++;
Guy Schalnat0d580581995-07-20 02:43:20 -05001279
Andreas Dilger47a0c421997-05-16 02:46:07 -05001280 png_ptr->zstream.next_in = (png_bytep)text;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001281 png_ptr->zstream.avail_in = (uInt)(length - (text - key));
1282 png_ptr->zstream.next_out = png_ptr->zbuf;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001283 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001284
1285 key_size = text - key;
1286 text_size = 0;
1287 text = NULL;
1288
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001289 while (png_ptr->zstream.avail_in)
Guy Schalnate5a37791996-06-05 15:50:50 -05001290 {
1291 int ret;
1292
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001293 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnate5a37791996-06-05 15:50:50 -05001294 if (ret != Z_OK && ret != Z_STREAM_END)
Guy Schalnat0d580581995-07-20 02:43:20 -05001295 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001296 if (png_ptr->zstream.msg != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001297 png_warning(png_ptr, png_ptr->zstream.msg);
Guy Schalnate5a37791996-06-05 15:50:50 -05001298 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001299 png_warning(png_ptr, msg);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001300 inflateReset(&png_ptr->zstream);
1301 png_ptr->zstream.avail_in = 0;
Guy Schalnate5a37791996-06-05 15:50:50 -05001302
Andreas Dilger47a0c421997-05-16 02:46:07 -05001303 if (text == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001304 {
1305 text_size = key_size + sizeof(msg) + 1;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001306 text = (png_charp)png_malloc(png_ptr, text_size);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001307 png_memcpy(text, key, key_size);
Guy Schalnate5a37791996-06-05 15:50:50 -05001308 }
1309
1310 text[text_size - 1] = '\0';
1311
1312 /* Copy what we can of the error message into the text chunk */
1313 text_size = length - (text - key) - 1;
1314 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001315 png_memcpy(text + key_size, msg, text_size + 1);
Guy Schalnate5a37791996-06-05 15:50:50 -05001316 break;
1317 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001318 if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
Guy Schalnate5a37791996-06-05 15:50:50 -05001319 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001320 if (text == NULL)
Guy Schalnate5a37791996-06-05 15:50:50 -05001321 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001322 text = (png_charp)png_malloc(png_ptr,
1323 png_ptr->zbuf_size - png_ptr->zstream.avail_out +
Guy Schalnate5a37791996-06-05 15:50:50 -05001324 key_size + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001325 png_memcpy(text + key_size, png_ptr->zbuf,
1326 png_ptr->zbuf_size - png_ptr->zstream.avail_out);
1327 png_memcpy(text, key, key_size);
1328 text_size = key_size + png_ptr->zbuf_size -
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001329 png_ptr->zstream.avail_out;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001330 *(text + text_size) = '\0';
Guy Schalnate5a37791996-06-05 15:50:50 -05001331 }
1332 else
1333 {
1334 png_charp tmp;
1335
1336 tmp = text;
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001337 text = (png_charp)png_malloc(png_ptr, text_size +
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001338 png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001339 png_memcpy(text, tmp, text_size);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001340 png_free(png_ptr, tmp);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001341 png_memcpy(text + text_size, png_ptr->zbuf,
1342 (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001343 text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001344 *(text + text_size) = '\0';
Guy Schalnate5a37791996-06-05 15:50:50 -05001345 }
1346 if (ret != Z_STREAM_END)
1347 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001348 png_ptr->zstream.next_out = png_ptr->zbuf;
1349 png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001350 }
1351 else
1352 {
1353 break;
1354 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001355 }
1356 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001357
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001358 inflateReset(&png_ptr->zstream);
1359 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05001360
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001361 png_free(png_ptr, key);
Guy Schalnate5a37791996-06-05 15:50:50 -05001362 key = text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001363 text += key_size;
Guy Schalnate5a37791996-06-05 15:50:50 -05001364 text_size -= key_size;
Guy Schalnat0d580581995-07-20 02:43:20 -05001365 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001366 else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */
1367 {
1368 png_size_t text_size;
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001369#if !defined(PNG_NO_STDIO)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001370 char umsg[50];
Guy Schalnat0d580581995-07-20 02:43:20 -05001371
Andreas Dilger47a0c421997-05-16 02:46:07 -05001372 sprintf(umsg, "Unknown zTXt compression type %d", comp_type);
1373 png_warning(png_ptr, umsg);
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001374#else
1375 png_warning(png_ptr, "Unknown zTXt compression type");
1376#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05001377
1378 /* Copy what we can of the error message into the text chunk */
1379 text_size = (png_size_t)length - (text - key) - 1;
1380 text_size = sizeof(msg) > text_size ? text_size : sizeof(msg);
1381 png_memcpy(text, msg, text_size + 1);
1382 }
1383
1384 text_ptr = (png_textp)png_malloc(png_ptr, sizeof(png_text));
1385 text_ptr->compression = comp_type;
1386 text_ptr->key = key;
1387 text_ptr->text = text;
1388
1389 png_set_text(png_ptr, info_ptr, text_ptr, 1);
1390
1391 png_free(png_ptr, text_ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -05001392}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001393#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001394
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001395/* This function is called when we haven't found a handler for a
1396 chunk. If there isn't a problem with the chunk itself (ie bad
Andreas Dilger47a0c421997-05-16 02:46:07 -05001397 chunk name, CRC, or a critical chunk), the chunk is silently ignored. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001398void
1399png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1400{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001401 png_debug(1, "in png_handle_unknown\n");
1402
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001403 /* In the future we can have code here that calls user-supplied
1404 * callback functions for unknown chunks before they are ignored or
1405 * cause an error.
1406 */
1407 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
1408
1409 if (!(png_ptr->chunk_name[0] & 0x20))
1410 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001411 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001412 }
1413
1414 if (png_ptr->mode & PNG_HAVE_IDAT)
1415 png_ptr->mode |= PNG_AFTER_IDAT;
1416
1417 png_crc_finish(png_ptr, length);
1418}
1419
1420/* This function is called to verify that a chunk name is valid.
1421 This function can't have the "critical chunk check" incorporated
Andreas Dilger47a0c421997-05-16 02:46:07 -05001422 into it, since in the future we will need to be able to call user
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001423 functions to handle unknown critical chunks after we check that
1424 the chunk name itself is valid. */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001425
1426#define isnonalpha(c) ((c) < 41 || (c) > 122 || ((c) > 90 && (c) < 97))
1427
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001428void
1429png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
1430{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001431 png_debug(1, "in png_check_chunk_name\n");
1432 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
1433 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001434 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06001435 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001436 }
1437}
1438
Guy Schalnat0d580581995-07-20 02:43:20 -05001439/* Combines the row recently read in with the previous row.
1440 This routine takes care of alpha and transparency if requested.
1441 This routine also handles the two methods of progressive display
1442 of interlaced images, depending on the mask value.
1443 The mask value describes which pixels are to be combined with
1444 the row. The pattern always repeats every 8 pixels, so just 8
1445 bits are needed. A one indicates the pixels is to be combined,
1446 a zero indicates the pixel is to be skipped. This is in addition
1447 to any alpha or transparency value associated with the pixel. If
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001448 you want all pixels to be combined, pass 0xff (255) in mask. */
Guy Schalnat0d580581995-07-20 02:43:20 -05001449void
Guy Schalnat6d764711995-12-19 03:22:19 -06001450png_combine_row(png_structp png_ptr, png_bytep row,
Guy Schalnat0d580581995-07-20 02:43:20 -05001451 int mask)
1452{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001453 png_debug(1,"in png_combine_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001454 if (mask == 0xff)
1455 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001456 png_memcpy(row, png_ptr->row_buf + 1,
Guy Schalnat0d580581995-07-20 02:43:20 -05001457 (png_size_t)((png_ptr->width *
1458 png_ptr->row_info.pixel_depth + 7) >> 3));
1459 }
1460 else
1461 {
1462 switch (png_ptr->row_info.pixel_depth)
1463 {
1464 case 1:
1465 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001466 png_bytep sp;
1467 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001468 int s_inc, s_start, s_end;
Guy Schalnat0d580581995-07-20 02:43:20 -05001469 int m;
1470 int shift;
1471 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001472
1473 sp = png_ptr->row_buf + 1;
1474 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001475 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001476#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1477 if (png_ptr->transformations & PNG_PACKSWAP)
1478 {
1479 s_start = 0;
1480 s_end = 7;
1481 s_inc = 1;
1482 }
1483 else
1484#endif
1485 {
1486 s_start = 7;
1487 s_end = 0;
1488 s_inc = -1;
1489 }
1490
1491 shift = s_start;
1492
Guy Schalnat0d580581995-07-20 02:43:20 -05001493 for (i = 0; i < png_ptr->width; i++)
1494 {
1495 if (m & mask)
1496 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001497 int value;
1498
Guy Schalnat0d580581995-07-20 02:43:20 -05001499 value = (*sp >> shift) & 0x1;
1500 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001501 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001502 }
1503
Andreas Dilger47a0c421997-05-16 02:46:07 -05001504 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001505 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001506 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001507 sp++;
1508 dp++;
1509 }
1510 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001511 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001512
1513 if (m == 1)
1514 m = 0x80;
1515 else
1516 m >>= 1;
1517 }
1518 break;
1519 }
1520 case 2:
1521 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001522 png_bytep sp;
1523 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001524 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001525 int m;
1526 int shift;
1527 png_uint_32 i;
1528 int value;
1529
1530 sp = png_ptr->row_buf + 1;
1531 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001532 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001533#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1534 if (png_ptr->transformations & PNG_PACKSWAP)
1535 {
1536 s_start = 0;
1537 s_end = 6;
1538 s_inc = 2;
1539 }
1540 else
1541#endif
1542 {
1543 s_start = 6;
1544 s_end = 0;
1545 s_inc = -2;
1546 }
1547
1548 shift = s_start;
1549
Guy Schalnat0d580581995-07-20 02:43:20 -05001550 for (i = 0; i < png_ptr->width; i++)
1551 {
1552 if (m & mask)
1553 {
1554 value = (*sp >> shift) & 0x3;
1555 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001556 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001557 }
1558
Andreas Dilger47a0c421997-05-16 02:46:07 -05001559 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001560 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001561 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001562 sp++;
1563 dp++;
1564 }
1565 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001566 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001567 if (m == 1)
1568 m = 0x80;
1569 else
1570 m >>= 1;
1571 }
1572 break;
1573 }
1574 case 4:
1575 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001576 png_bytep sp;
1577 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001578 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001579 int m;
1580 int shift;
1581 png_uint_32 i;
1582 int value;
1583
1584 sp = png_ptr->row_buf + 1;
1585 dp = row;
Guy Schalnat0d580581995-07-20 02:43:20 -05001586 m = 0x80;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001587#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1588 if (png_ptr->transformations & PNG_PACKSWAP)
1589 {
1590 s_start = 0;
1591 s_end = 4;
1592 s_inc = 4;
1593 }
1594 else
1595#endif
1596 {
1597 s_start = 4;
1598 s_end = 0;
1599 s_inc = -4;
1600 }
1601 shift = s_start;
1602
Guy Schalnat0d580581995-07-20 02:43:20 -05001603 for (i = 0; i < png_ptr->width; i++)
1604 {
1605 if (m & mask)
1606 {
1607 value = (*sp >> shift) & 0xf;
1608 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001609 *dp |= (png_byte)(value << shift);
Guy Schalnat0d580581995-07-20 02:43:20 -05001610 }
1611
Andreas Dilger47a0c421997-05-16 02:46:07 -05001612 if (shift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001613 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001614 shift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001615 sp++;
1616 dp++;
1617 }
1618 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001619 shift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001620 if (m == 1)
1621 m = 0x80;
1622 else
1623 m >>= 1;
1624 }
1625 break;
1626 }
1627 default:
1628 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001629 png_bytep sp;
1630 png_bytep dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001631 png_size_t pixel_bytes;
1632 png_uint_32 i;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001633 png_byte m;
Guy Schalnat0d580581995-07-20 02:43:20 -05001634
1635 pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
1636
1637 sp = png_ptr->row_buf + 1;
1638 dp = row;
1639 m = 0x80;
1640 for (i = 0; i < png_ptr->width; i++)
1641 {
1642 if (m & mask)
1643 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001644 png_memcpy(dp, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001645 }
1646
1647 sp += pixel_bytes;
1648 dp += pixel_bytes;
1649
1650 if (m == 1)
1651 m = 0x80;
1652 else
1653 m >>= 1;
1654 }
1655 break;
1656 }
1657 }
1658 }
1659}
1660
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001661#if defined(PNG_READ_INTERLACING_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05001662void
Andreas Dilger47a0c421997-05-16 02:46:07 -05001663png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
1664 png_uint_32 transformations)
Guy Schalnat0d580581995-07-20 02:43:20 -05001665{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001666 png_debug(1,"in png_do_read_interlace\n");
1667 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05001668 {
1669 png_uint_32 final_width;
1670
1671 final_width = row_info->width * png_pass_inc[pass];
1672
1673 switch (row_info->pixel_depth)
1674 {
1675 case 1:
1676 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001677 png_bytep sp, dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001678 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001679 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001680 png_byte v;
1681 png_uint_32 i;
1682 int j;
1683
1684 sp = row + (png_size_t)((row_info->width - 1) >> 3);
Guy Schalnat0d580581995-07-20 02:43:20 -05001685 dp = row + (png_size_t)((final_width - 1) >> 3);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001686#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1687 if (transformations & PNG_PACKSWAP)
1688 {
1689 sshift = (int)((row_info->width + 7) & 7);
1690 dshift = (int)((final_width + 7) & 7);
1691 s_start = 7;
1692 s_end = 0;
1693 s_inc = -1;
1694 }
1695 else
1696#endif
1697 {
1698 sshift = 7 - (int)((row_info->width + 7) & 7);
1699 dshift = 7 - (int)((final_width + 7) & 7);
1700 s_start = 0;
1701 s_end = 7;
1702 s_inc = 1;
1703 }
1704
Guy Schalnat0d580581995-07-20 02:43:20 -05001705 for (i = row_info->width; i; i--)
1706 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001707 v = (png_byte)((*sp >> sshift) & 0x1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001708 for (j = 0; j < png_pass_inc[pass]; j++)
1709 {
1710 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
1711 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001712 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001713 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001714 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001715 dp--;
1716 }
1717 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001718 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001719 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001720 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001721 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001722 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001723 sp--;
1724 }
1725 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001726 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001727 }
1728 break;
1729 }
1730 case 2:
1731 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001732 png_bytep sp, dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001733 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001734 int s_start, s_end, s_inc;
1735 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001736
1737 sp = row + (png_size_t)((row_info->width - 1) >> 2);
Guy Schalnat0d580581995-07-20 02:43:20 -05001738 dp = row + (png_size_t)((final_width - 1) >> 2);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001739#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1740 if (transformations & PNG_PACKSWAP)
1741 {
1742 sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
1743 dshift = (png_size_t)(((final_width + 3) & 3) << 1);
1744 s_start = 6;
1745 s_end = 0;
1746 s_inc = -2;
1747 }
1748 else
1749#endif
1750 {
1751 sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
1752 dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
1753 s_start = 0;
1754 s_end = 6;
1755 s_inc = 2;
1756 }
1757
Guy Schalnat0d580581995-07-20 02:43:20 -05001758 for (i = row_info->width; i; i--)
1759 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001760 png_byte v;
1761 int j;
1762
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001763 v = (png_byte)((*sp >> sshift) & 0x3);
Guy Schalnat0d580581995-07-20 02:43:20 -05001764 for (j = 0; j < png_pass_inc[pass]; j++)
1765 {
1766 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001767 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001768 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001769 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001770 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001771 dp--;
1772 }
1773 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001774 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001775 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001776 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001777 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001778 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001779 sp--;
1780 }
1781 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001782 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001783 }
1784 break;
1785 }
1786 case 4:
1787 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001788 png_bytep sp, dp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001789 int sshift, dshift;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001790 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001791 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05001792
1793 sp = row + (png_size_t)((row_info->width - 1) >> 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001794 dp = row + (png_size_t)((final_width - 1) >> 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001795#if defined(PNG_READ_PACKSWAP_SUPPORTED)
1796 if (transformations & PNG_PACKSWAP)
1797 {
1798 sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
1799 dshift = (png_size_t)(((final_width + 1) & 1) << 2);
1800 s_start = 4;
1801 s_end = 0;
1802 s_inc = -4;
1803 }
1804 else
1805#endif
1806 {
1807 sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
1808 dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
1809 s_start = 0;
1810 s_end = 4;
1811 s_inc = 4;
1812 }
1813
Guy Schalnat0d580581995-07-20 02:43:20 -05001814 for (i = row_info->width; i; i--)
1815 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001816 png_byte v;
1817 int j;
1818
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001819 v = (png_byte)((*sp >> sshift) & 0xf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001820 for (j = 0; j < png_pass_inc[pass]; j++)
1821 {
1822 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
Guy Schalnat4ee97b01996-01-16 01:51:56 -06001823 *dp |= (png_byte)(v << dshift);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001824 if (dshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001825 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001826 dshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001827 dp--;
1828 }
1829 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001830 dshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001831 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001832 if (sshift == s_end)
Guy Schalnat0d580581995-07-20 02:43:20 -05001833 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001834 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05001835 sp--;
1836 }
1837 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05001838 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05001839 }
1840 break;
1841 }
1842 default:
1843 {
Guy Schalnat6d764711995-12-19 03:22:19 -06001844 png_bytep sp, dp;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001845 png_uint_32 i;
1846 png_size_t pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001847
1848 pixel_bytes = (row_info->pixel_depth >> 3);
1849
Andreas Dilger47a0c421997-05-16 02:46:07 -05001850 sp = row + (row_info->width - 1) * pixel_bytes;
1851 dp = row + (final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05001852 for (i = row_info->width; i; i--)
1853 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001854 png_byte v[8];
1855 int j;
1856
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001857 png_memcpy(v, sp, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001858 for (j = 0; j < png_pass_inc[pass]; j++)
1859 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001860 png_memcpy(dp, v, pixel_bytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05001861 dp -= pixel_bytes;
1862 }
1863 sp -= pixel_bytes;
1864 }
1865 break;
1866 }
1867 }
1868 row_info->width = final_width;
1869 row_info->rowbytes = ((final_width *
1870 (png_uint_32)row_info->pixel_depth + 7) >> 3);
1871 }
1872}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001873#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001874
1875void
Guy Schalnate5a37791996-06-05 15:50:50 -05001876png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Guy Schalnat6d764711995-12-19 03:22:19 -06001877 png_bytep prev_row, int filter)
Guy Schalnat0d580581995-07-20 02:43:20 -05001878{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001879 png_debug(1, "in png_read_filter_row\n");
1880 png_debug2(2,"row = %d, filter = %d\n", png_ptr->row_number, filter);
1881
Guy Schalnat0d580581995-07-20 02:43:20 -05001882 switch (filter)
1883 {
Andreas Dilger47a0c421997-05-16 02:46:07 -05001884 case PNG_FILTER_VALUE_NONE:
Guy Schalnat0d580581995-07-20 02:43:20 -05001885 break;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001886 case PNG_FILTER_VALUE_SUB:
Guy Schalnat0d580581995-07-20 02:43:20 -05001887 {
1888 png_uint_32 i;
1889 int bpp;
Guy Schalnat6d764711995-12-19 03:22:19 -06001890 png_bytep rp;
1891 png_bytep lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001892
1893 bpp = (row_info->pixel_depth + 7) / 8;
1894 for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
1895 i < row_info->rowbytes; i++, rp++, lp++)
1896 {
1897 *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
1898 }
1899 break;
1900 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001901 case PNG_FILTER_VALUE_UP:
Guy Schalnat0d580581995-07-20 02:43:20 -05001902 {
1903 png_uint_32 i;
Guy Schalnat6d764711995-12-19 03:22:19 -06001904 png_bytep rp;
1905 png_bytep pp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001906
1907 for (i = 0, rp = row, pp = prev_row;
1908 i < row_info->rowbytes; i++, rp++, pp++)
1909 {
1910 *rp = (png_byte)(((int)(*rp) + (int)(*pp)) & 0xff);
1911 }
1912 break;
1913 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001914 case PNG_FILTER_VALUE_AVG:
Guy Schalnat0d580581995-07-20 02:43:20 -05001915 {
1916 png_uint_32 i;
1917 int bpp;
Guy Schalnat6d764711995-12-19 03:22:19 -06001918 png_bytep rp;
1919 png_bytep pp;
1920 png_bytep lp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001921
1922 bpp = (row_info->pixel_depth + 7) / 8;
1923 for (i = 0, rp = row, pp = prev_row;
1924 i < (png_uint_32)bpp; i++, rp++, pp++)
1925 {
1926 *rp = (png_byte)(((int)(*rp) +
1927 ((int)(*pp) / 2)) & 0xff);
1928 }
1929 for (lp = row; i < row_info->rowbytes; i++, rp++, lp++, pp++)
1930 {
1931 *rp = (png_byte)(((int)(*rp) +
1932 (int)(*pp + *lp) / 2) & 0xff);
1933 }
1934 break;
1935 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001936 case PNG_FILTER_VALUE_PAETH:
Guy Schalnat0d580581995-07-20 02:43:20 -05001937 {
1938 int bpp;
1939 png_uint_32 i;
Guy Schalnat6d764711995-12-19 03:22:19 -06001940 png_bytep rp;
1941 png_bytep pp;
1942 png_bytep lp;
1943 png_bytep cp;
Guy Schalnat0d580581995-07-20 02:43:20 -05001944
1945 bpp = (row_info->pixel_depth + 7) / 8;
1946 for (i = 0, rp = row, pp = prev_row,
1947 lp = row - bpp, cp = prev_row - bpp;
1948 i < row_info->rowbytes; i++, rp++, pp++, lp++, cp++)
1949 {
1950 int a, b, c, pa, pb, pc, p;
1951
1952 b = *pp;
1953 if (i >= (png_uint_32)bpp)
1954 {
1955 c = *cp;
1956 a = *lp;
1957 }
1958 else
1959 {
1960 a = c = 0;
1961 }
1962 p = a + b - c;
1963 pa = abs(p - a);
1964 pb = abs(p - b);
1965 pc = abs(p - c);
1966
1967 if (pa <= pb && pa <= pc)
1968 p = a;
1969 else if (pb <= pc)
1970 p = b;
1971 else
1972 p = c;
1973
1974 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
1975 }
1976 break;
1977 }
1978 default:
Guy Schalnate5a37791996-06-05 15:50:50 -05001979 png_error(png_ptr, "Bad adaptive filter type");
Guy Schalnat0d580581995-07-20 02:43:20 -05001980 break;
1981 }
1982}
1983
1984void
Guy Schalnat6d764711995-12-19 03:22:19 -06001985png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05001986{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001987 png_debug(1, "in png_read_finish_row\n");
Guy Schalnat0d580581995-07-20 02:43:20 -05001988 png_ptr->row_number++;
1989 if (png_ptr->row_number < png_ptr->num_rows)
1990 return;
1991
1992 if (png_ptr->interlaced)
1993 {
1994 png_ptr->row_number = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001995 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05001996 do
1997 {
1998 png_ptr->pass++;
1999 if (png_ptr->pass >= 7)
2000 break;
2001 png_ptr->iwidth = (png_ptr->width +
2002 png_pass_inc[png_ptr->pass] - 1 -
2003 png_pass_start[png_ptr->pass]) /
2004 png_pass_inc[png_ptr->pass];
2005 png_ptr->irowbytes = ((png_ptr->iwidth *
2006 png_ptr->pixel_depth + 7) >> 3) + 1;
2007 if (!(png_ptr->transformations & PNG_INTERLACE))
2008 {
2009 png_ptr->num_rows = (png_ptr->height +
2010 png_pass_yinc[png_ptr->pass] - 1 -
2011 png_pass_ystart[png_ptr->pass]) /
2012 png_pass_yinc[png_ptr->pass];
2013 if (!(png_ptr->num_rows))
2014 continue;
2015 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002016 if (png_ptr->transformations & PNG_INTERLACE)
2017 break;
Guy Schalnat0d580581995-07-20 02:43:20 -05002018 } while (png_ptr->iwidth == 0);
2019
2020 if (png_ptr->pass < 7)
2021 return;
2022 }
2023
Guy Schalnate5a37791996-06-05 15:50:50 -05002024 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05002025 {
2026 char extra;
2027 int ret;
2028
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002029 png_ptr->zstream.next_out = (Byte *)&extra;
2030 png_ptr->zstream.avail_out = (uInt)1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002031 do
2032 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002033 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05002034 {
2035 while (!png_ptr->idat_size)
2036 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002037 png_byte chunk_length[4];
Guy Schalnat0d580581995-07-20 02:43:20 -05002038
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002039 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05002040
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002041 png_read_data(png_ptr, chunk_length, 4);
2042 png_ptr->idat_size = png_get_uint_32(chunk_length);
2043
Guy Schalnat0d580581995-07-20 02:43:20 -05002044 png_reset_crc(png_ptr);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002045 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
2046 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06002047 png_error(png_ptr, "Not enough image data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002048
2049 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002050 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
2051 png_ptr->zstream.next_in = png_ptr->zbuf;
Guy Schalnat0d580581995-07-20 02:43:20 -05002052 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002053 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
2054 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
2055 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05002056 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002057 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Guy Schalnat0d580581995-07-20 02:43:20 -05002058 if (ret == Z_STREAM_END)
2059 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002060 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Guy Schalnat0d580581995-07-20 02:43:20 -05002061 png_ptr->idat_size)
Guy Schalnat6d764711995-12-19 03:22:19 -06002062 png_error(png_ptr, "Extra compressed data");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002063 png_ptr->mode |= PNG_AFTER_IDAT;
2064 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05002065 break;
2066 }
2067 if (ret != Z_OK)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002068 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Guy Schalnate5a37791996-06-05 15:50:50 -05002069 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05002070
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002071 if (!(png_ptr->zstream.avail_out))
Guy Schalnat6d764711995-12-19 03:22:19 -06002072 png_error(png_ptr, "Extra compressed data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002073
2074 } while (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002075 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002076 }
2077
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002078 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Guy Schalnat6d764711995-12-19 03:22:19 -06002079 png_error(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05002080
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002081 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05002082
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002083 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002084}
2085
2086void
Guy Schalnat6d764711995-12-19 03:22:19 -06002087png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002088{
2089 int max_pixel_depth;
2090 png_uint_32 rowbytes;
2091
Andreas Dilger47a0c421997-05-16 02:46:07 -05002092 png_debug(1, "in png_read_start_row\n");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002093 png_ptr->zstream.avail_in = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05002094 png_init_read_transformations(png_ptr);
2095 if (png_ptr->interlaced)
2096 {
2097 if (!(png_ptr->transformations & PNG_INTERLACE))
2098 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
2099 png_pass_ystart[0]) / png_pass_yinc[0];
2100 else
2101 png_ptr->num_rows = png_ptr->height;
2102
2103 png_ptr->iwidth = (png_ptr->width +
2104 png_pass_inc[png_ptr->pass] - 1 -
2105 png_pass_start[png_ptr->pass]) /
2106 png_pass_inc[png_ptr->pass];
2107 png_ptr->irowbytes = ((png_ptr->iwidth *
2108 png_ptr->pixel_depth + 7) >> 3) + 1;
2109 }
2110 else
2111 {
2112 png_ptr->num_rows = png_ptr->height;
2113 png_ptr->iwidth = png_ptr->width;
2114 png_ptr->irowbytes = png_ptr->rowbytes + 1;
2115 }
Guy Schalnat0d580581995-07-20 02:43:20 -05002116 max_pixel_depth = png_ptr->pixel_depth;
2117
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002118#if defined(PNG_READ_PACK_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002119 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05002120 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002121#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002122
Guy Schalnate5a37791996-06-05 15:50:50 -05002123#if defined(PNG_READ_EXPAND_SUPPORTED)
2124 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05002125 {
2126 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2127 {
2128 if (png_ptr->num_trans)
2129 max_pixel_depth = 32;
2130 else
2131 max_pixel_depth = 24;
2132 }
2133 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
2134 {
2135 if (max_pixel_depth < 8)
2136 max_pixel_depth = 8;
2137 if (png_ptr->num_trans)
2138 max_pixel_depth *= 2;
2139 }
2140 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
2141 {
2142 if (png_ptr->num_trans)
2143 {
2144 max_pixel_depth *= 4;
2145 max_pixel_depth /= 3;
2146 }
2147 }
2148 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002149#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002150
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002151#if defined(PNG_READ_FILLER_SUPPORTED)
2152 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05002153 {
2154 if (max_pixel_depth < 32)
2155 max_pixel_depth = 32;
2156 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002157#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002158
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002159#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
Guy Schalnat0d580581995-07-20 02:43:20 -05002160 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
2161 {
2162 if ((png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
2163 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2164 {
2165 if (max_pixel_depth <= 16)
2166 max_pixel_depth = 32;
2167 else if (max_pixel_depth <= 32)
2168 max_pixel_depth = 64;
2169 }
2170 else
2171 {
2172 if (max_pixel_depth <= 8)
2173 max_pixel_depth = 24;
2174 else if (max_pixel_depth <= 16)
2175 max_pixel_depth = 48;
2176 }
2177 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002178#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002179
2180 /* align the width on the next larger 8 pixels. Mainly used
2181 for interlacing */
2182 rowbytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
2183 /* calculate the maximum bytes needed, adding a byte and a pixel
2184 for safety sake */
2185 rowbytes = ((rowbytes * (png_uint_32)max_pixel_depth + 7) >> 3) +
2186 1 + ((max_pixel_depth + 7) >> 3);
2187#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002188 if (rowbytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002189 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002190#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002191 png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, rowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002192
2193#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002194 if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05002195 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05002196#endif
Andreas Dilger47a0c421997-05-16 02:46:07 -05002197 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05002198
Andreas Dilger47a0c421997-05-16 02:46:07 -05002199 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
2200
2201 png_debug1(3, "width = %d,\n", png_ptr->width);
2202 png_debug1(3, "height = %d,\n", png_ptr->height);
2203 png_debug1(3, "iwidth = %d,\n", png_ptr->iwidth);
2204 png_debug1(3, "num_rows = %d\n", png_ptr->num_rows);
2205 png_debug1(3, "rowbytes = %d,\n", png_ptr->rowbytes);
2206 png_debug1(3, "irowbytes = %d,\n", png_ptr->irowbytes);
Guy Schalnat0d580581995-07-20 02:43:20 -05002207
Guy Schalnate5a37791996-06-05 15:50:50 -05002208 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05002209}