blob: 08a6e6329c5d8669833a4afbaa1b640ceed36939 [file] [log] [blame]
Glenn Randers-Pehrsone6474622006-03-04 16:50:47 -06001
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-Pehrson65a24d02011-04-01 20:41:53 -05004 * Last changed in libpng 1.5.3 [(PENDING RELEASE)]
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06005 * Copyright (c) 1998-2011 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrson3e61d792009-06-24 09:31:28 -050012 *
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050013 * This file contains routines that are only called from within
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060014 * libpng itself during the course of reading an image.
15 */
Guy Schalnat0d580581995-07-20 02:43:20 -050016
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050017#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050018
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060019#ifdef PNG_READ_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -050020
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060021#define png_strtod(p,a,b) strtod(a,b)
22
23png_uint_32 PNGAPI
24png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
25{
26 png_uint_32 uval = png_get_uint_32(buf);
27
28 if (uval > PNG_UINT_31_MAX)
29 png_error(png_ptr, "PNG unsigned integer out of range");
30
31 return (uval);
32}
33
34#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
35/* The following is a variation on the above for use with the fixed
36 * point values used for gAMA and cHRM. Instead of png_error it
37 * issues a warning and returns (-1) - an invalid value because both
38 * gAMA and cHRM use *unsigned* integers for fixed point values.
39 */
40#define PNG_FIXED_ERROR (-1)
41
42static png_fixed_point /* PRIVATE */
43png_get_fixed_point(png_structp png_ptr, png_const_bytep buf)
44{
45 png_uint_32 uval = png_get_uint_32(buf);
46
47 if (uval <= PNG_UINT_31_MAX)
48 return (png_fixed_point)uval; /* known to be in range */
49
50 /* The caller can turn off the warning by passing NULL. */
51 if (png_ptr != NULL)
52 png_warning(png_ptr, "PNG fixed point integer out of range");
53
54 return PNG_FIXED_ERROR;
55}
56#endif
57
58#ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED
59/* NOTE: the read macros will obscure these definitions, so that if
60 * PNG_USE_READ_MACROS is set the library will not use them internally,
61 * but the APIs will still be available externally.
62 *
63 * The parentheses around "PNGAPI function_name" in the following three
64 * functions are necessary because they allow the macros to co-exist with
65 * these (unused but exported) functions.
66 */
67
68/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
69png_uint_32 (PNGAPI
70png_get_uint_32)(png_const_bytep buf)
71{
72 png_uint_32 uval =
73 ((png_uint_32)(*(buf )) << 24) +
74 ((png_uint_32)(*(buf + 1)) << 16) +
75 ((png_uint_32)(*(buf + 2)) << 8) +
76 ((png_uint_32)(*(buf + 3)) ) ;
77
78 return uval;
Guy Schalnat0d580581995-07-20 02:43:20 -050079}
80
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050081/* Grab a signed 32-bit integer from a buffer in big-endian format. The
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060082 * data is stored in the PNG file in two's complement format and there
83 * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore
84 * the following code does a two's complement to native conversion.
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050085 */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060086png_int_32 (PNGAPI
87png_get_int_32)(png_const_bytep buf)
Andreas Dilger47a0c421997-05-16 02:46:07 -050088{
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060089 png_uint_32 uval = png_get_uint_32(buf);
90 if ((uval & 0x80000000L) == 0) /* non-negative */
91 return uval;
Andreas Dilger47a0c421997-05-16 02:46:07 -050092
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060093 uval = (uval ^ 0xffffffffL) + 1; /* 2's complement: -x = ~x+1 */
94 return -(png_int_32)uval;
Andreas Dilger47a0c421997-05-16 02:46:07 -050095}
Andreas Dilger47a0c421997-05-16 02:46:07 -050096
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -050097/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -060098png_uint_16 (PNGAPI
99png_get_uint_16)(png_const_bytep buf)
Guy Schalnat0d580581995-07-20 02:43:20 -0500100{
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600101 /* ANSI-C requires an int value to accomodate at least 16 bits so this
102 * works and allows the compiler not to worry about possible narrowing
103 * on 32 bit systems. (Pre-ANSI systems did not make integers smaller
104 * than 16 bits either.)
105 */
106 unsigned int val =
107 ((unsigned int)(*buf) << 8) +
108 ((unsigned int)(*(buf + 1)));
Guy Schalnat0d580581995-07-20 02:43:20 -0500109
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600110 return (png_uint_16)val;
Guy Schalnat0d580581995-07-20 02:43:20 -0500111}
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600112
113#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */
114
115/* Read and check the PNG file signature */
116void /* PRIVATE */
117png_read_sig(png_structp png_ptr, png_infop info_ptr)
118{
119 png_size_t num_checked, num_to_check;
120
121 /* Exit if the user application does not expect a signature. */
122 if (png_ptr->sig_bytes >= 8)
123 return;
124
125 num_checked = png_ptr->sig_bytes;
126 num_to_check = 8 - num_checked;
127
128#ifdef PNG_IO_STATE_SUPPORTED
129 png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE;
130#endif
131
132 /* The signature must be serialized in a single I/O call. */
133 png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
134 png_ptr->sig_bytes = 8;
135
136 if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
137 {
138 if (num_checked < 4 &&
139 png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
140 png_error(png_ptr, "Not a PNG file");
141 else
142 png_error(png_ptr, "PNG file corrupted by ASCII conversion");
143 }
144 if (num_checked < 3)
145 png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
146}
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -0600147
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500148/* Read the chunk header (length + type name).
149 * Put the type name into png_ptr->chunk_name, and return the length.
150 */
151png_uint_32 /* PRIVATE */
152png_read_chunk_header(png_structp png_ptr)
153{
154 png_byte buf[8];
155 png_uint_32 length;
156
157#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500158 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR;
159#endif
160
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600161 /* Read the length and the chunk name.
162 * This must be performed in a single I/O call.
163 */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500164 png_read_data(png_ptr, buf, 8);
165 length = png_get_uint_31(png_ptr, buf);
166
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600167 /* Put the chunk name into png_ptr->chunk_name. */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500168 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
169
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600170 png_debug2(0, "Reading %s chunk, length = %u",
171 png_ptr->chunk_name, length);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500172
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600173 /* Reset the crc and run it over the chunk name. */
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500174 png_reset_crc(png_ptr);
175 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
176
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600177 /* Check to see if chunk name is valid. */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500178 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
179
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500180#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500181 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA;
182#endif
183
184 return length;
185}
186
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500187/* Read data, and (optionally) run it through the CRC. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500188void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500189png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500190{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500191 if (png_ptr == NULL)
192 return;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600193
Guy Schalnat6d764711995-12-19 03:22:19 -0600194 png_read_data(png_ptr, buf, length);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500195 png_calculate_crc(png_ptr, buf, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500196}
197
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600198/* Optionally skip data and then check the CRC. Depending on whether we
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500199 * are reading a ancillary or critical chunk, and how the program has set
200 * things up, we may calculate the CRC on the data and print a message.
201 * Returns '1' if there was a CRC error, '0' otherwise.
202 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500203int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600204png_crc_finish(png_structp png_ptr, png_uint_32 skip)
Guy Schalnat0d580581995-07-20 02:43:20 -0500205{
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500206 png_size_t i;
207 png_size_t istop = png_ptr->zbuf_size;
Guy Schalnat0d580581995-07-20 02:43:20 -0500208
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -0500209 for (i = (png_size_t)skip; i > istop; i -= istop)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600210 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500211 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
Guy Schalnat0d580581995-07-20 02:43:20 -0500212 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600213
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500214 if (i)
Guy Schalnat0d580581995-07-20 02:43:20 -0500215 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -0500216 png_crc_read(png_ptr, png_ptr->zbuf, i);
Guy Schalnat0d580581995-07-20 02:43:20 -0500217 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600218
Andreas Dilger47a0c421997-05-16 02:46:07 -0500219 if (png_crc_error(png_ptr))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600220 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500221 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500222 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500223 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600224 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600225 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600226 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600227 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600228
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600229 else
230 {
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500231 png_chunk_benign_error(png_ptr, "CRC error");
232 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600233 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600234
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600235 return (1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600236 }
237
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600238 return (0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500239}
240
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -0600241/* Compare the CRC stored in the PNG file with that calculated by libpng from
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500242 * the data it has read thus far.
243 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500244int /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600245png_crc_error(png_structp png_ptr)
246{
247 png_byte crc_bytes[4];
248 png_uint_32 crc;
Andreas Dilger47a0c421997-05-16 02:46:07 -0500249 int need_crc = 1;
250
251 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
252 {
253 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
254 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
255 need_crc = 0;
256 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600257
Andreas Dilger47a0c421997-05-16 02:46:07 -0500258 else /* critical */
259 {
260 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
261 need_crc = 0;
262 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600263
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500264#ifdef PNG_IO_STATE_SUPPORTED
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500265 png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC;
266#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500267
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600268 /* The chunk CRC must be serialized in a single I/O call. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600269 png_read_data(png_ptr, crc_bytes, 4);
270
Andreas Dilger47a0c421997-05-16 02:46:07 -0500271 if (need_crc)
272 {
273 crc = png_get_uint_32(crc_bytes);
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600274 return ((int)(crc != png_ptr->crc));
Andreas Dilger47a0c421997-05-16 02:46:07 -0500275 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600276
Andreas Dilger47a0c421997-05-16 02:46:07 -0500277 else
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600278 return (0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600279}
280
Glenn Randers-Pehrson5975f312011-04-01 13:15:36 -0500281#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600282static png_size_t
283png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
284 png_bytep output, png_size_t output_size)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600285{
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600286 png_size_t count = 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600287
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600288 /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
289 * even necessarily handle 65536 bytes) because the type uInt is "16 bits or
290 * more". Consequently it is necessary to chunk the input to zlib. This
291 * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value
292 * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a
293 * lower value in pngpriv.h and this may sometimes have a performance
294 * advantage, because it forces access of the input data to be separated from
295 * at least some of the use by some period of time.
296 */
297 png_ptr->zstream.next_in = data;
298 /* avail_in is set below from 'size' */
299 png_ptr->zstream.avail_in = 0;
300
301 while (1)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600302 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600303 int ret, avail;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600304
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600305 /* The setting of 'avail_in' used to be outside the loop, by setting it
306 * inside it is possible to chunk the input to zlib and simply rely on
307 * zlib to advance the 'next_in' pointer. This allows arbitrary amounts o
308 * data to be passed through zlib at the unavoidable cost of requiring a
309 * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX
310 * input bytes.
311 */
312 if (png_ptr->zstream.avail_in == 0 && size > 0)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600313 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600314 if (size <= ZLIB_IO_MAX)
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600315 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600316 /* The value is less than ZLIB_IO_MAX so the cast is safe: */
317 png_ptr->zstream.avail_in = (uInt)size;
318 size = 0;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600319 }
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500320
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600321 else
322 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600323 png_ptr->zstream.avail_in = ZLIB_IO_MAX;
324 size -= ZLIB_IO_MAX;
Glenn Randers-Pehrson72cda2d2010-03-06 08:18:03 -0600325 }
Glenn Randers-Pehrson9d51afc2010-02-12 20:12:56 -0600326 }
327
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600328 /* Reset the output buffer each time round - we empty it
329 * after every inflate call.
330 */
331 png_ptr->zstream.next_out = png_ptr->zbuf;
332 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
333
334 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
335 avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
336
337 /* First copy/count any new output - but only if we didn't
338 * get an error code.
339 */
340 if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
341 {
342 png_size_t space = avail; /* > 0, see above */
343
344 if (output != 0 && output_size > count)
345 {
346 png_size_t copy = output_size - count;
347
348 if (space < copy)
349 copy = space;
350
351 png_memcpy(output + count, png_ptr->zbuf, copy);
352 }
353 count += space;
354 }
355
356 if (ret == Z_OK)
357 continue;
358
359 /* Termination conditions - always reset the zstream, it
360 * must be left in inflateInit state.
361 */
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600362 png_ptr->zstream.avail_in = 0;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600363 inflateReset(&png_ptr->zstream);
364
365 if (ret == Z_STREAM_END)
366 return count; /* NOTE: may be zero. */
367
368 /* Now handle the error codes - the API always returns 0
369 * and the error message is dumped into the uncompressed
370 * buffer if available.
371 */
John Bowler88b77cc2011-05-05 06:49:55 -0500372# ifdef PNG_WARNINGS_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600373 {
John Bowler88b77cc2011-05-05 06:49:55 -0500374 png_const_charp msg;
375
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600376 if (png_ptr->zstream.msg != 0)
377 msg = png_ptr->zstream.msg;
378
John Bowler88b77cc2011-05-05 06:49:55 -0500379 else switch (ret)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600380 {
John Bowler88b77cc2011-05-05 06:49:55 -0500381 case Z_BUF_ERROR:
382 msg = "Buffer error in compressed datastream";
383 break;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600384
John Bowler88b77cc2011-05-05 06:49:55 -0500385 case Z_DATA_ERROR:
386 msg = "Data error in compressed datastream";
387 break;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600388
John Bowler88b77cc2011-05-05 06:49:55 -0500389 default:
390 msg = "Incomplete compressed datastream";
391 break;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600392 }
393
John Bowler88b77cc2011-05-05 06:49:55 -0500394 png_chunk_warning(png_ptr, msg);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600395 }
John Bowler88b77cc2011-05-05 06:49:55 -0500396# endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600397
398 /* 0 means an error - notice that this code simply ignores
399 * zero length compressed chunks as a result.
400 */
401 return 0;
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600402 }
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600403}
404
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600405/*
406 * Decompress trailing data in a chunk. The assumption is that chunkdata
407 * points at an allocated area holding the contents of a chunk with a
408 * trailing compressed part. What we get back is an allocated area
409 * holding the original prefix part and an uncompressed version of the
410 * trailing part (the malloc area passed in is freed).
411 */
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500412void /* PRIVATE */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500413png_decompress_chunk(png_structp png_ptr, int comp_type,
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600414 png_size_t chunklength,
415 png_size_t prefix_size, png_size_t *newlength)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600416{
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600417 /* The caller should guarantee this */
418 if (prefix_size > chunklength)
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600419 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600420 /* The recovery is to delete the chunk. */
421 png_warning(png_ptr, "invalid chunklength");
422 prefix_size = 0; /* To delete everything */
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -0600423 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600424
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600425 else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600426 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600427 png_size_t expanded_size = png_inflate(png_ptr,
428 (png_bytep)(png_ptr->chunkdata + prefix_size),
429 chunklength - prefix_size,
Glenn Randers-Pehrsonb75b2412011-04-16 19:35:05 -0500430 0, /* output */
431 0); /* output size */
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600432
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600433 /* Now check the limits on this chunk - if the limit fails the
434 * compressed data will be removed, the prefix will remain.
435 */
436#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
437 if (png_ptr->user_chunk_malloc_max &&
438 (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600439#else
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600440# ifdef PNG_USER_CHUNK_MALLOC_MAX
441 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
442 prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
443# endif
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600444#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600445 png_warning(png_ptr, "Exceeded size limit while expanding chunk");
446
447 /* If the size is zero either there was an error and a message
448 * has already been output (warning) or the size really is zero
449 * and we have nothing to do - the code will exit through the
450 * error case below.
451 */
452#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
453 defined(PNG_USER_CHUNK_MALLOC_MAX)
454 else if (expanded_size > 0)
455#else
456 if (expanded_size > 0)
457#endif
458 {
459 /* Success (maybe) - really uncompress the chunk. */
460 png_size_t new_size = 0;
461 png_charp text = png_malloc_warn(png_ptr,
462 prefix_size + expanded_size + 1);
463
464 if (text != NULL)
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600465 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600466 png_memcpy(text, png_ptr->chunkdata, prefix_size);
467 new_size = png_inflate(png_ptr,
468 (png_bytep)(png_ptr->chunkdata + prefix_size),
469 chunklength - prefix_size,
470 (png_bytep)(text + prefix_size), expanded_size);
471 text[prefix_size + expanded_size] = 0; /* just in case */
472
473 if (new_size == expanded_size)
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600474 {
475 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600476 png_ptr->chunkdata = text;
477 *newlength = prefix_size + expanded_size;
478 return; /* The success return! */
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600479 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600480
481 png_warning(png_ptr, "png_inflate logic error");
482 png_free(png_ptr, text);
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600483 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600484
485 else
486 png_warning(png_ptr, "Not enough memory to decompress chunk");
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600487 }
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -0600488 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600489
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600490 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
491 {
John Bowler88b77cc2011-05-05 06:49:55 -0500492 PNG_WARNING_PARAMETERS(p)
493 png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type);
494 png_formatted_warning(png_ptr, p, "Unknown zTXt compression type @1");
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600495
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600496 /* The recovery is to simply drop the data. */
Glenn Randers-Pehrson9b0956f2010-02-12 11:17:22 -0600497 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600498
499 /* Generic error return - leave the prefix, delete the compressed
500 * data, reallocate the chunkdata to remove the potentially large
501 * amount of compressed data.
502 */
503 {
504 png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
505
506 if (text != NULL)
507 {
508 if (prefix_size > 0)
509 png_memcpy(text, png_ptr->chunkdata, prefix_size);
510
511 png_free(png_ptr, png_ptr->chunkdata);
512 png_ptr->chunkdata = text;
513
514 /* This is an extra zero in the 'uncompressed' part. */
515 *(png_ptr->chunkdata + prefix_size) = 0x00;
516 }
517 /* Ignore a malloc error here - it is safe. */
518 }
519
520 *newlength = prefix_size;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600521}
Glenn Randers-Pehrson5975f312011-04-01 13:15:36 -0500522#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600523
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500524/* Read and check the IDHR chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500525void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600526png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500527{
528 png_byte buf[13];
529 png_uint_32 width, height;
530 int bit_depth, color_type, compression_type, filter_type;
531 int interlace_type;
532
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500533 png_debug(1, "in png_handle_IHDR");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500534
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -0600535 if (png_ptr->mode & PNG_HAVE_IHDR)
Guy Schalnate5a37791996-06-05 15:50:50 -0500536 png_error(png_ptr, "Out of place IHDR");
537
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500538 /* Check the length */
Guy Schalnat0d580581995-07-20 02:43:20 -0500539 if (length != 13)
Guy Schalnat6d764711995-12-19 03:22:19 -0600540 png_error(png_ptr, "Invalid IHDR chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -0500541
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600542 png_ptr->mode |= PNG_HAVE_IHDR;
543
Guy Schalnat0d580581995-07-20 02:43:20 -0500544 png_crc_read(png_ptr, buf, 13);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600545 png_crc_finish(png_ptr, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500546
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500547 width = png_get_uint_31(png_ptr, buf);
548 height = png_get_uint_31(png_ptr, buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -0500549 bit_depth = buf[8];
550 color_type = buf[9];
551 compression_type = buf[10];
552 filter_type = buf[11];
553 interlace_type = buf[12];
554
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500555 /* Set internal variables */
Guy Schalnat0d580581995-07-20 02:43:20 -0500556 png_ptr->width = width;
557 png_ptr->height = height;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600558 png_ptr->bit_depth = (png_byte)bit_depth;
559 png_ptr->interlaced = (png_byte)interlace_type;
560 png_ptr->color_type = (png_byte)color_type;
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500561#ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson2ad31ae2000-12-15 08:54:42 -0600562 png_ptr->filter_type = (png_byte)filter_type;
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500563#endif
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500564 png_ptr->compression_type = (png_byte)compression_type;
Guy Schalnat0d580581995-07-20 02:43:20 -0500565
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500566 /* Find number of channels */
Guy Schalnat0d580581995-07-20 02:43:20 -0500567 switch (png_ptr->color_type)
568 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600569 default: /* invalid, png_set_IHDR calls png_error */
Andreas Dilger47a0c421997-05-16 02:46:07 -0500570 case PNG_COLOR_TYPE_GRAY:
571 case PNG_COLOR_TYPE_PALETTE:
Guy Schalnat0d580581995-07-20 02:43:20 -0500572 png_ptr->channels = 1;
573 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500574
Andreas Dilger47a0c421997-05-16 02:46:07 -0500575 case PNG_COLOR_TYPE_RGB:
Guy Schalnat0d580581995-07-20 02:43:20 -0500576 png_ptr->channels = 3;
577 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500578
Andreas Dilger47a0c421997-05-16 02:46:07 -0500579 case PNG_COLOR_TYPE_GRAY_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500580 png_ptr->channels = 2;
581 break;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500582
Andreas Dilger47a0c421997-05-16 02:46:07 -0500583 case PNG_COLOR_TYPE_RGB_ALPHA:
Guy Schalnat0d580581995-07-20 02:43:20 -0500584 png_ptr->channels = 4;
585 break;
586 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600587
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500588 /* Set up other useful info */
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600589 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -0600590 png_ptr->channels);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500591 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500592 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
593 png_debug1(3, "channels = %d", png_ptr->channels);
Glenn Randers-Pehrsonb764c602011-01-14 21:18:37 -0600594 png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes);
Andreas Dilger47a0c421997-05-16 02:46:07 -0500595 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600596 color_type, interlace_type, compression_type, filter_type);
Guy Schalnat0d580581995-07-20 02:43:20 -0500597}
598
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500599/* Read and check the palette */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500600void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600601png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500602{
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600603 png_color palette[PNG_MAX_PALETTE_LENGTH];
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600604 int num, i;
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500605#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500606 png_colorp pal_ptr;
607#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500608
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500609 png_debug(1, "in png_handle_PLTE");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500610
Guy Schalnate5a37791996-06-05 15:50:50 -0500611 if (!(png_ptr->mode & PNG_HAVE_IHDR))
612 png_error(png_ptr, "Missing IHDR before PLTE");
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500613
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600614 else if (png_ptr->mode & PNG_HAVE_IDAT)
615 {
616 png_warning(png_ptr, "Invalid PLTE after IDAT");
617 png_crc_finish(png_ptr, length);
618 return;
619 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500620
Guy Schalnate5a37791996-06-05 15:50:50 -0500621 else if (png_ptr->mode & PNG_HAVE_PLTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600622 png_error(png_ptr, "Duplicate PLTE chunk");
623
624 png_ptr->mode |= PNG_HAVE_PLTE;
Guy Schalnate5a37791996-06-05 15:50:50 -0500625
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500626 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
627 {
628 png_warning(png_ptr,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600629 "Ignoring PLTE chunk in grayscale PNG");
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -0500630 png_crc_finish(png_ptr, length);
631 return;
632 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600633
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500634#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -0500635 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
636 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600637 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500638 return;
639 }
640#endif
641
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -0600642 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
Guy Schalnate5a37791996-06-05 15:50:50 -0500643 {
644 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
645 {
646 png_warning(png_ptr, "Invalid palette chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600647 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -0500648 return;
649 }
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500650
Guy Schalnate5a37791996-06-05 15:50:50 -0500651 else
652 {
653 png_error(png_ptr, "Invalid palette chunk");
654 }
655 }
Guy Schalnat0d580581995-07-20 02:43:20 -0500656
657 num = (int)length / 3;
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500658
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -0500659#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500660 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
661 {
662 png_byte buf[3];
663
664 png_crc_read(png_ptr, buf, 3);
665 pal_ptr->red = buf[0];
666 pal_ptr->green = buf[1];
667 pal_ptr->blue = buf[2];
668 }
669#else
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600670 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -0500671 {
672 png_byte buf[3];
673
674 png_crc_read(png_ptr, buf, 3);
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500675 /* Don't depend upon png_color being any order */
Guy Schalnat0d580581995-07-20 02:43:20 -0500676 palette[i].red = buf[0];
677 palette[i].green = buf[1];
678 palette[i].blue = buf[2];
679 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -0500680#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600681
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600682 /* If we actually need the PLTE chunk (ie for a paletted image), we do
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500683 * whatever the normal CRC configuration tells us. However, if we
684 * have an RGB image, the PLTE can be considered ancillary, so
685 * we will act as though it is.
686 */
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500687#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600688 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600689#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600690 {
Andreas Dilger47a0c421997-05-16 02:46:07 -0500691 png_crc_finish(png_ptr, 0);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600692 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600693
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -0500694#ifndef PNG_READ_OPT_PLTE_SUPPORTED
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600695 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
696 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600697 /* If we don't want to use the data from an ancillary chunk,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600698 * we have two options: an error abort, or a warning and we
699 * ignore the data in this chunk (which should be OK, since
700 * it's considered ancillary for a RGB or RGBA image).
701 */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600702 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
703 {
704 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
705 {
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500706 png_chunk_benign_error(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600707 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600708
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600709 else
710 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600711 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600712 return;
713 }
714 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600715
Andreas Dilger47a0c421997-05-16 02:46:07 -0500716 /* Otherwise, we (optionally) emit a warning and use the chunk. */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600717 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
718 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -0600719 png_chunk_warning(png_ptr, "CRC error");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600720 }
721 }
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -0600722#endif
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500723
Andreas Dilger47a0c421997-05-16 02:46:07 -0500724 png_set_PLTE(png_ptr, info_ptr, palette, num);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500725
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500726#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500727 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
728 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600729 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500730 {
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500731 if (png_ptr->num_trans > (png_uint_16)num)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500732 {
733 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500734 png_ptr->num_trans = (png_uint_16)num;
735 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600736
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500737 if (info_ptr->num_trans > (png_uint_16)num)
738 {
739 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
740 info_ptr->num_trans = (png_uint_16)num;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -0500741 }
742 }
743 }
744#endif
745
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600746}
Guy Schalnate5a37791996-06-05 15:50:50 -0500747
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500748void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600749png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
750{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500751 png_debug(1, "in png_handle_IEND");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500752
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600753 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
754 {
755 png_error(png_ptr, "No image in file");
756 }
757
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600758 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600759
760 if (length != 0)
761 {
762 png_warning(png_ptr, "Incorrect IEND chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600763 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600764
Andreas Dilger47a0c421997-05-16 02:46:07 -0500765 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500766
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600767 PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
Guy Schalnat0d580581995-07-20 02:43:20 -0500768}
769
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500770#ifdef PNG_READ_gAMA_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500771void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600772png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500773{
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600774 png_fixed_point igamma;
Guy Schalnat0d580581995-07-20 02:43:20 -0500775 png_byte buf[4];
776
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500777 png_debug(1, "in png_handle_gAMA");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500778
Guy Schalnate5a37791996-06-05 15:50:50 -0500779 if (!(png_ptr->mode & PNG_HAVE_IHDR))
780 png_error(png_ptr, "Missing IHDR before gAMA");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600781
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600782 else if (png_ptr->mode & PNG_HAVE_IDAT)
783 {
784 png_warning(png_ptr, "Invalid gAMA after IDAT");
785 png_crc_finish(png_ptr, length);
786 return;
787 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600788
Guy Schalnate5a37791996-06-05 15:50:50 -0500789 else if (png_ptr->mode & PNG_HAVE_PLTE)
790 /* Should be an error, but we can cope with it */
791 png_warning(png_ptr, "Out of place gAMA chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600792
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500793 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500794#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600795 && !(info_ptr->valid & PNG_INFO_sRGB)
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600796#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600797 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600798 {
799 png_warning(png_ptr, "Duplicate gAMA chunk");
800 png_crc_finish(png_ptr, length);
801 return;
802 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500803
Guy Schalnat0d580581995-07-20 02:43:20 -0500804 if (length != 4)
805 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600806 png_warning(png_ptr, "Incorrect gAMA chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600807 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500808 return;
809 }
810
811 png_crc_read(png_ptr, buf, 4);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600812
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600813 if (png_crc_finish(png_ptr, 0))
814 return;
815
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600816 igamma = png_get_fixed_point(NULL, buf);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500817
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600818 /* Check for zero gamma or an error. */
819 if (igamma <= 0)
820 {
821 png_warning(png_ptr,
822 "Ignoring gAMA chunk with out of range gamma");
823
824 return;
825 }
826
827# ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -0600828 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600829 {
Glenn Randers-Pehrsond029a752004-08-09 21:50:32 -0500830 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600831 {
John Bowler88b77cc2011-05-05 06:49:55 -0500832 PNG_WARNING_PARAMETERS(p)
833 png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma);
834 png_formatted_warning(png_ptr, p,
835 "Ignoring incorrect gAMA value @1 when sRGB is also present");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600836 return;
837 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600838 }
839# endif /* PNG_READ_sRGB_SUPPORTED */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600840
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600841# ifdef PNG_READ_GAMMA_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600842 /* Gamma correction on read is supported. */
843 png_ptr->gamma = igamma;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600844# endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600845 /* And set the 'info' structure members. */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600846 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
Guy Schalnat0d580581995-07-20 02:43:20 -0500847}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500848#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500849
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500850#ifdef PNG_READ_sBIT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500851void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600852png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500853{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500854 png_size_t truelen;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600855 png_byte buf[4];
Guy Schalnat69b14481996-01-10 02:56:49 -0600856
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500857 png_debug(1, "in png_handle_sBIT");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500858
Guy Schalnat69b14481996-01-10 02:56:49 -0600859 buf[0] = buf[1] = buf[2] = buf[3] = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -0500860
Guy Schalnate5a37791996-06-05 15:50:50 -0500861 if (!(png_ptr->mode & PNG_HAVE_IHDR))
862 png_error(png_ptr, "Missing IHDR before sBIT");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600863
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600864 else if (png_ptr->mode & PNG_HAVE_IDAT)
865 {
866 png_warning(png_ptr, "Invalid sBIT after IDAT");
867 png_crc_finish(png_ptr, length);
868 return;
869 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600870
Guy Schalnate5a37791996-06-05 15:50:50 -0500871 else if (png_ptr->mode & PNG_HAVE_PLTE)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600872 {
Guy Schalnate5a37791996-06-05 15:50:50 -0500873 /* Should be an error, but we can cope with it */
874 png_warning(png_ptr, "Out of place sBIT chunk");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600875 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600876
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500877 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600878 {
879 png_warning(png_ptr, "Duplicate sBIT chunk");
880 png_crc_finish(png_ptr, length);
881 return;
882 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500883
Guy Schalnat0d580581995-07-20 02:43:20 -0500884 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600885 truelen = 3;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600886
Guy Schalnat0d580581995-07-20 02:43:20 -0500887 else
Andreas Dilger47a0c421997-05-16 02:46:07 -0500888 truelen = (png_size_t)png_ptr->channels;
Guy Schalnat0d580581995-07-20 02:43:20 -0500889
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -0500890 if (length != truelen || length > 4)
Guy Schalnat0d580581995-07-20 02:43:20 -0500891 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600892 png_warning(png_ptr, "Incorrect sBIT chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600893 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600894 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500895 }
896
Andreas Dilger47a0c421997-05-16 02:46:07 -0500897 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600898
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600899 if (png_crc_finish(png_ptr, 0))
900 return;
901
Guy Schalnat0d580581995-07-20 02:43:20 -0500902 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
903 {
Guy Schalnat6d764711995-12-19 03:22:19 -0600904 png_ptr->sig_bit.red = buf[0];
905 png_ptr->sig_bit.green = buf[1];
906 png_ptr->sig_bit.blue = buf[2];
907 png_ptr->sig_bit.alpha = buf[3];
Guy Schalnat0d580581995-07-20 02:43:20 -0500908 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600909
Guy Schalnat0d580581995-07-20 02:43:20 -0500910 else
911 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600912 png_ptr->sig_bit.gray = buf[0];
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600913 png_ptr->sig_bit.red = buf[0];
914 png_ptr->sig_bit.green = buf[0];
915 png_ptr->sig_bit.blue = buf[0];
Guy Schalnat6d764711995-12-19 03:22:19 -0600916 png_ptr->sig_bit.alpha = buf[1];
Guy Schalnat0d580581995-07-20 02:43:20 -0500917 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600918
Andreas Dilger47a0c421997-05-16 02:46:07 -0500919 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
Guy Schalnat0d580581995-07-20 02:43:20 -0500920}
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500921#endif
Guy Schalnat0d580581995-07-20 02:43:20 -0500922
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500923#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500924void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600925png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500926{
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500927 png_byte buf[32];
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600928 png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue,
929 y_blue;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -0600930
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500931 png_debug(1, "in png_handle_cHRM");
Andreas Dilger47a0c421997-05-16 02:46:07 -0500932
Guy Schalnate5a37791996-06-05 15:50:50 -0500933 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600934 png_error(png_ptr, "Missing IHDR before cHRM");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600935
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600936 else if (png_ptr->mode & PNG_HAVE_IDAT)
937 {
938 png_warning(png_ptr, "Invalid cHRM after IDAT");
939 png_crc_finish(png_ptr, length);
940 return;
941 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600942
Guy Schalnate5a37791996-06-05 15:50:50 -0500943 else if (png_ptr->mode & PNG_HAVE_PLTE)
944 /* Should be an error, but we can cope with it */
945 png_warning(png_ptr, "Missing PLTE before cHRM");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600946
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -0500947 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600948# ifdef PNG_READ_sRGB_SUPPORTED
949 && !(info_ptr->valid & PNG_INFO_sRGB)
950# endif
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -0600951 )
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600952 {
953 png_warning(png_ptr, "Duplicate cHRM chunk");
954 png_crc_finish(png_ptr, length);
955 return;
956 }
Guy Schalnate5a37791996-06-05 15:50:50 -0500957
Guy Schalnat0d580581995-07-20 02:43:20 -0500958 if (length != 32)
959 {
Guy Schalnat69b14481996-01-10 02:56:49 -0600960 png_warning(png_ptr, "Incorrect cHRM chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600961 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -0600962 return;
Guy Schalnat0d580581995-07-20 02:43:20 -0500963 }
964
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500965 png_crc_read(png_ptr, buf, 32);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600966
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500967 if (png_crc_finish(png_ptr, 0))
968 return;
969
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600970 x_white = png_get_fixed_point(NULL, buf);
971 y_white = png_get_fixed_point(NULL, buf + 4);
972 x_red = png_get_fixed_point(NULL, buf + 8);
973 y_red = png_get_fixed_point(NULL, buf + 12);
974 x_green = png_get_fixed_point(NULL, buf + 16);
975 y_green = png_get_fixed_point(NULL, buf + 20);
976 x_blue = png_get_fixed_point(NULL, buf + 24);
977 y_blue = png_get_fixed_point(NULL, buf + 28);
Glenn Randers-Pehrson33893092010-10-23 13:20:18 -0500978
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600979 if (x_white == PNG_FIXED_ERROR ||
980 y_white == PNG_FIXED_ERROR ||
981 x_red == PNG_FIXED_ERROR ||
982 y_red == PNG_FIXED_ERROR ||
983 x_green == PNG_FIXED_ERROR ||
984 y_green == PNG_FIXED_ERROR ||
985 x_blue == PNG_FIXED_ERROR ||
986 y_blue == PNG_FIXED_ERROR)
987 {
988 png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities");
989 return;
990 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600991
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500992#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson6bc53be2006-06-16 07:52:03 -0500993 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -0600994 {
995 if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) ||
996 PNG_OUT_OF_RANGE(y_white, 32900, 1000) ||
997 PNG_OUT_OF_RANGE(x_red, 64000L, 1000) ||
998 PNG_OUT_OF_RANGE(y_red, 33000, 1000) ||
999 PNG_OUT_OF_RANGE(x_green, 30000, 1000) ||
1000 PNG_OUT_OF_RANGE(y_green, 60000L, 1000) ||
1001 PNG_OUT_OF_RANGE(x_blue, 15000, 1000) ||
1002 PNG_OUT_OF_RANGE(y_blue, 6000, 1000))
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05001003 {
John Bowler88b77cc2011-05-05 06:49:55 -05001004 PNG_WARNING_PARAMETERS(p)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001005
John Bowler88b77cc2011-05-05 06:49:55 -05001006 png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white);
1007 png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white);
1008 png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red);
1009 png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red);
1010 png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green);
1011 png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green);
1012 png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue);
1013 png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001014
John Bowler88b77cc2011-05-05 06:49:55 -05001015 png_formatted_warning(png_ptr, p,
1016 "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) "
1017 "when sRGB is also present");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001018 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001019 return;
1020 }
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001021#endif /* PNG_READ_sRGB_SUPPORTED */
1022
John Bowlercb0b2962011-05-12 21:48:29 -05001023#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
1024 /* Store the _white values as default coefficients for the rgb to gray
1025 * operation if it is supported.
1026 */
1027 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
1028 {
1029 /* png_set_background has not been called, the coefficients must be in
1030 * range for the following to work without overflow.
1031 */
1032 if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17))
1033 {
1034 /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray
1035 * transformation are simply the normalized Y values for red, green and
1036 * blue scaled by 32768.
1037 */
1038 png_uint_32 w = y_red + y_green + y_blue;
1039
1040 png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red *
1041 32768)/w);
1042 png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green
1043 * 32768)/w);
1044 png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue *
1045 32768)/w);
1046 }
1047 }
1048#endif
1049
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001050 png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
1051 x_green, y_green, x_blue, y_blue);
Guy Schalnat0d580581995-07-20 02:43:20 -05001052}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001053#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001054
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001055#ifdef PNG_READ_sRGB_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001056void /* PRIVATE */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001057png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1058{
Glenn Randers-Pehrsonc4a2ae61998-01-16 22:06:18 -06001059 int intent;
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001060 png_byte buf[1];
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001061
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001062 png_debug(1, "in png_handle_sRGB");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001063
1064 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1065 png_error(png_ptr, "Missing IHDR before sRGB");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001066
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001067 else if (png_ptr->mode & PNG_HAVE_IDAT)
1068 {
1069 png_warning(png_ptr, "Invalid sRGB after IDAT");
1070 png_crc_finish(png_ptr, length);
1071 return;
1072 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001073
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001074 else if (png_ptr->mode & PNG_HAVE_PLTE)
1075 /* Should be an error, but we can cope with it */
1076 png_warning(png_ptr, "Out of place sRGB chunk");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001077
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001078 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001079 {
1080 png_warning(png_ptr, "Duplicate sRGB chunk");
1081 png_crc_finish(png_ptr, length);
1082 return;
1083 }
1084
1085 if (length != 1)
1086 {
1087 png_warning(png_ptr, "Incorrect sRGB chunk length");
1088 png_crc_finish(png_ptr, length);
1089 return;
1090 }
1091
1092 png_crc_read(png_ptr, buf, 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001093
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001094 if (png_crc_finish(png_ptr, 0))
1095 return;
1096
1097 intent = buf[0];
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001098
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001099 /* Check for bad intent */
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001100 if (intent >= PNG_sRGB_INTENT_LAST)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06001101 {
1102 png_warning(png_ptr, "Unknown sRGB intent");
1103 return;
1104 }
1105
Glenn Randers-Pehrson46f61e21998-01-30 21:45:12 -06001106#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001107 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001108 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001109 if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001110 {
John Bowler88b77cc2011-05-05 06:49:55 -05001111 PNG_WARNING_PARAMETERS(p)
1112
1113 png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed,
1114 info_ptr->gamma);
1115
1116 png_formatted_warning(png_ptr, p,
1117 "Ignoring incorrect gAMA value @1 when sRGB is also present");
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001118 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001119 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001120#endif /* PNG_READ_gAMA_SUPPORTED */
1121
1122#ifdef PNG_READ_cHRM_SUPPORTED
Glenn Randers-Pehrson170b70c2006-03-10 10:19:04 -06001123 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001124 if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) ||
1125 PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) ||
1126 PNG_OUT_OF_RANGE(info_ptr->x_red, 64000L, 1000) ||
1127 PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) ||
1128 PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) ||
1129 PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) ||
1130 PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) ||
1131 PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000))
1132 {
1133 png_warning(png_ptr,
1134 "Ignoring incorrect cHRM value when sRGB is also present");
1135 }
Glenn Randers-Pehrson2687fcc1998-01-07 20:54:20 -06001136#endif /* PNG_READ_cHRM_SUPPORTED */
1137
1138 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1139}
1140#endif /* PNG_READ_sRGB_SUPPORTED */
1141
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001142#ifdef PNG_READ_iCCP_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001143void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001144png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1145/* Note: this does not properly handle chunks that are > 64K under DOS */
1146{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001147 png_byte compression_type;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -06001148 png_bytep pC;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001149 png_charp profile;
1150 png_uint_32 skip = 0;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001151 png_uint_32 profile_size;
1152 png_alloc_size_t profile_length;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06001153 png_size_t slength, prefix_length, data_length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001154
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001155 png_debug(1, "in png_handle_iCCP");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001156
1157 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1158 png_error(png_ptr, "Missing IHDR before iCCP");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001159
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001160 else if (png_ptr->mode & PNG_HAVE_IDAT)
1161 {
1162 png_warning(png_ptr, "Invalid iCCP after IDAT");
1163 png_crc_finish(png_ptr, length);
1164 return;
1165 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001166
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001167 else if (png_ptr->mode & PNG_HAVE_PLTE)
1168 /* Should be an error, but we can cope with it */
1169 png_warning(png_ptr, "Out of place iCCP chunk");
1170
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001171 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001172 {
1173 png_warning(png_ptr, "Duplicate iCCP chunk");
1174 png_crc_finish(png_ptr, length);
1175 return;
1176 }
1177
1178#ifdef PNG_MAX_MALLOC_64K
1179 if (length > (png_uint_32)65535L)
1180 {
1181 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1182 skip = length - (png_uint_32)65535L;
1183 length = (png_uint_32)65535L;
1184 }
1185#endif
1186
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001187 png_free(png_ptr, png_ptr->chunkdata);
1188 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001189 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001190 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001191
1192 if (png_crc_finish(png_ptr, skip))
1193 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001194 png_free(png_ptr, png_ptr->chunkdata);
1195 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001196 return;
1197 }
1198
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001199 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001200
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001201 for (profile = png_ptr->chunkdata; *profile; profile++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001202 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001203
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001204 ++profile;
1205
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001206 /* There should be at least one zero (the compression type byte)
1207 * following the separator, and we should be on it
1208 */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001209 if (profile >= png_ptr->chunkdata + slength - 1)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001210 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001211 png_free(png_ptr, png_ptr->chunkdata);
1212 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001213 png_warning(png_ptr, "Malformed iCCP chunk");
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001214 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001215 }
1216
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001217 /* Compression_type should always be zero */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001218 compression_type = *profile++;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001219
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001220 if (compression_type)
1221 {
1222 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001223 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001224 wrote nonzero) */
1225 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001226
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001227 prefix_length = profile - png_ptr->chunkdata;
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05001228 png_decompress_chunk(png_ptr, compression_type,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001229 slength, prefix_length, &data_length);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001230
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001231 profile_length = data_length - prefix_length;
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001232
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001233 if (prefix_length > data_length || profile_length < 4)
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001234 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001235 png_free(png_ptr, png_ptr->chunkdata);
1236 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonb1828932001-06-23 08:03:17 -05001237 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1238 return;
1239 }
1240
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06001241 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001242 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001243 profile_size = ((*(pC )) << 24) |
1244 ((*(pC + 1)) << 16) |
1245 ((*(pC + 2)) << 8) |
1246 ((*(pC + 3)) );
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001247
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001248 /* NOTE: the following guarantees that 'profile_length' fits into 32 bits,
1249 * because profile_size is a 32 bit value.
1250 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001251 if (profile_size < profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001252 profile_length = profile_size;
1253
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001254 /* And the following guarantees that profile_size == profile_length. */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001255 if (profile_size > profile_length)
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001256 {
John Bowler88b77cc2011-05-05 06:49:55 -05001257 PNG_WARNING_PARAMETERS(p)
1258
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001259 png_free(png_ptr, png_ptr->chunkdata);
1260 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001261
John Bowler88b77cc2011-05-05 06:49:55 -05001262 png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size);
1263 png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length);
1264 png_formatted_warning(png_ptr, p,
1265 "Ignoring iCCP chunk with declared size = @1 and actual length = @2");
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -06001266 return;
1267 }
1268
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001269 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001270 compression_type, (png_bytep)png_ptr->chunkdata + prefix_length,
1271 profile_size);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001272 png_free(png_ptr, png_ptr->chunkdata);
1273 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001274}
1275#endif /* PNG_READ_iCCP_SUPPORTED */
1276
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001277#ifdef PNG_READ_sPLT_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001278void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001279png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1280/* Note: this does not properly handle chunks that are > 64K under DOS */
1281{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001282 png_bytep entry_start;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06001283 png_sPLT_t new_palette;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001284 png_sPLT_entryp pp;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001285 png_uint_32 data_length;
1286 int entry_size, i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001287 png_uint_32 skip = 0;
1288 png_size_t slength;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001289 png_uint_32 dl;
1290 png_size_t max_dl;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001291
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001292 png_debug(1, "in png_handle_sPLT");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001293
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001294#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05001295
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001296 if (png_ptr->user_chunk_cache_max != 0)
1297 {
1298 if (png_ptr->user_chunk_cache_max == 1)
1299 {
1300 png_crc_finish(png_ptr, length);
1301 return;
1302 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001303
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05001304 if (--png_ptr->user_chunk_cache_max == 1)
1305 {
1306 png_warning(png_ptr, "No space in chunk cache for sPLT");
1307 png_crc_finish(png_ptr, length);
1308 return;
1309 }
1310 }
1311#endif
1312
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001313 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1314 png_error(png_ptr, "Missing IHDR before sPLT");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001315
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001316 else if (png_ptr->mode & PNG_HAVE_IDAT)
1317 {
1318 png_warning(png_ptr, "Invalid sPLT after IDAT");
1319 png_crc_finish(png_ptr, length);
1320 return;
1321 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001322
1323#ifdef PNG_MAX_MALLOC_64K
1324 if (length > (png_uint_32)65535L)
1325 {
1326 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1327 skip = length - (png_uint_32)65535L;
1328 length = (png_uint_32)65535L;
1329 }
1330#endif
1331
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001332 png_free(png_ptr, png_ptr->chunkdata);
1333 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001334
1335 /* WARNING: this may break if size_t is less than 32 bits; it is assumed
1336 * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
1337 * potential breakage point if the types in pngconf.h aren't exactly right.
1338 */
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05001339 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001340 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001341
1342 if (png_crc_finish(png_ptr, skip))
1343 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001344 png_free(png_ptr, png_ptr->chunkdata);
1345 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001346 return;
1347 }
1348
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001349 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001350
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06001351 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1352 entry_start++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001353 /* Empty loop to find end of name */ ;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001354
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001355 ++entry_start;
1356
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001357 /* A sample depth should follow the separator, and we should be on it */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001358 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001359 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001360 png_free(png_ptr, png_ptr->chunkdata);
1361 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05001362 png_warning(png_ptr, "malformed sPLT chunk");
1363 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001364 }
1365
1366 new_palette.depth = *entry_start++;
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06001367 entry_size = (new_palette.depth == 8 ? 6 : 10);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001368 /* This must fit in a png_uint_32 because it is derived from the original
1369 * chunk data length (and use 'length', not 'slength' here for clarity -
1370 * they are guaranteed to be the same, see the tests above.)
1371 */
1372 data_length = length - (png_uint_32)(entry_start -
1373 (png_bytep)png_ptr->chunkdata);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001374
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001375 /* Integrity-check the data length */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001376 if (data_length % entry_size)
1377 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001378 png_free(png_ptr, png_ptr->chunkdata);
1379 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson3097f612001-05-07 14:52:45 -05001380 png_warning(png_ptr, "sPLT chunk has bad length");
1381 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001382 }
1383
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001384 dl = (png_int_32)(data_length / entry_size);
1385 max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry);
1386
1387 if (dl > max_dl)
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001388 {
1389 png_warning(png_ptr, "sPLT chunk too long");
1390 return;
1391 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001392
1393 new_palette.nentries = (png_int_32)(data_length / entry_size);
1394
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001395 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001396 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001397
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001398 if (new_palette.entries == NULL)
1399 {
1400 png_warning(png_ptr, "sPLT chunk requires too much memory");
1401 return;
1402 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001403
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05001404#ifdef PNG_POINTER_INDEXING_SUPPORTED
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001405 for (i = 0; i < new_palette.nentries; i++)
1406 {
Glenn Randers-Pehrson90b878c2009-10-07 12:44:35 -05001407 pp = new_palette.entries + i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001408
1409 if (new_palette.depth == 8)
1410 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001411 pp->red = *entry_start++;
1412 pp->green = *entry_start++;
1413 pp->blue = *entry_start++;
1414 pp->alpha = *entry_start++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001415 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001416
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001417 else
1418 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001419 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1420 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1421 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1422 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001423 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001424
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001425 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1426 }
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001427#else
1428 pp = new_palette.entries;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001429
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001430 for (i = 0; i < new_palette.nentries; i++)
1431 {
1432
1433 if (new_palette.depth == 8)
1434 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001435 pp[i].red = *entry_start++;
1436 pp[i].green = *entry_start++;
1437 pp[i].blue = *entry_start++;
1438 pp[i].alpha = *entry_start++;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001439 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001440
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001441 else
1442 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001443 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1444 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1445 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1446 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001447 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001448
Glenn Randers-Pehrsonf27592a2011-03-21 18:05:40 -05001449 pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2;
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05001450 }
1451#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001452
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001453 /* Discard all chunk data except the name and stash that */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001454 new_palette.name = png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001455
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06001456 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001457
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05001458 png_free(png_ptr, png_ptr->chunkdata);
1459 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001460 png_free(png_ptr, new_palette.entries);
1461}
1462#endif /* PNG_READ_sPLT_SUPPORTED */
1463
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001464#ifdef PNG_READ_tRNS_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001465void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001466png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001467{
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001468 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001469
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001470 png_debug(1, "in png_handle_tRNS");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001471
Guy Schalnate5a37791996-06-05 15:50:50 -05001472 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1473 png_error(png_ptr, "Missing IHDR before tRNS");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001474
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001475 else if (png_ptr->mode & PNG_HAVE_IDAT)
1476 {
1477 png_warning(png_ptr, "Invalid tRNS after IDAT");
1478 png_crc_finish(png_ptr, length);
1479 return;
1480 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001481
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001482 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001483 {
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001484 png_warning(png_ptr, "Duplicate tRNS chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001485 png_crc_finish(png_ptr, length);
1486 return;
1487 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001488
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001489 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Guy Schalnat0d580581995-07-20 02:43:20 -05001490 {
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001491 png_byte buf[2];
Guy Schalnat0d580581995-07-20 02:43:20 -05001492
1493 if (length != 2)
1494 {
Guy Schalnat69b14481996-01-10 02:56:49 -06001495 png_warning(png_ptr, "Incorrect tRNS chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001496 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001497 return;
1498 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001499
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001500 png_crc_read(png_ptr, buf, 2);
1501 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001502 png_ptr->trans_color.gray = png_get_uint_16(buf);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001503 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001504
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001505 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1506 {
1507 png_byte buf[6];
1508
1509 if (length != 6)
1510 {
1511 png_warning(png_ptr, "Incorrect tRNS chunk length");
1512 png_crc_finish(png_ptr, length);
1513 return;
1514 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001515
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001516 png_crc_read(png_ptr, buf, (png_size_t)length);
1517 png_ptr->num_trans = 1;
Glenn Randers-Pehrson56f63962008-10-06 10:16:17 -05001518 png_ptr->trans_color.red = png_get_uint_16(buf);
1519 png_ptr->trans_color.green = png_get_uint_16(buf + 2);
1520 png_ptr->trans_color.blue = png_get_uint_16(buf + 4);
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001521 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001522
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001523 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1524 {
1525 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1526 {
1527 /* Should be an error, but we can cope with it. */
1528 png_warning(png_ptr, "Missing PLTE before tRNS");
1529 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001530
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001531 if (length > (png_uint_32)png_ptr->num_palette ||
1532 length > PNG_MAX_PALETTE_LENGTH)
1533 {
1534 png_warning(png_ptr, "Incorrect tRNS chunk length");
1535 png_crc_finish(png_ptr, length);
1536 return;
1537 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001538
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001539 if (length == 0)
1540 {
1541 png_warning(png_ptr, "Zero length tRNS chunk");
1542 png_crc_finish(png_ptr, length);
1543 return;
1544 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001545
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05001546 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1547 png_ptr->num_trans = (png_uint_16)length;
1548 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001549
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001550 else
Guy Schalnate5a37791996-06-05 15:50:50 -05001551 {
1552 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001553 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001554 return;
1555 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001556
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001557 if (png_crc_finish(png_ptr, 0))
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001558 {
1559 png_ptr->num_trans = 0;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001560 return;
Glenn Randers-Pehrsona7dbcba2007-05-15 16:16:34 -05001561 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001562
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001563 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001564 &(png_ptr->trans_color));
Guy Schalnat0d580581995-07-20 02:43:20 -05001565}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001566#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001567
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001568#ifdef PNG_READ_bKGD_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001569void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001570png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001571{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001572 png_size_t truelen;
Guy Schalnat0d580581995-07-20 02:43:20 -05001573 png_byte buf[6];
John Bowlercb0b2962011-05-12 21:48:29 -05001574 png_color_16 background;
Guy Schalnat0d580581995-07-20 02:43:20 -05001575
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001576 png_debug(1, "in png_handle_bKGD");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001577
Guy Schalnate5a37791996-06-05 15:50:50 -05001578 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1579 png_error(png_ptr, "Missing IHDR before bKGD");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001580
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001581 else if (png_ptr->mode & PNG_HAVE_IDAT)
1582 {
1583 png_warning(png_ptr, "Invalid bKGD after IDAT");
1584 png_crc_finish(png_ptr, length);
1585 return;
1586 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001587
Guy Schalnate5a37791996-06-05 15:50:50 -05001588 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001589 !(png_ptr->mode & PNG_HAVE_PLTE))
Guy Schalnate5a37791996-06-05 15:50:50 -05001590 {
1591 png_warning(png_ptr, "Missing PLTE before bKGD");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001592 png_crc_finish(png_ptr, length);
1593 return;
1594 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001595
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001596 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001597 {
1598 png_warning(png_ptr, "Duplicate bKGD chunk");
1599 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001600 return;
1601 }
1602
Guy Schalnat0d580581995-07-20 02:43:20 -05001603 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1604 truelen = 1;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001605
Guy Schalnat0d580581995-07-20 02:43:20 -05001606 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1607 truelen = 6;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001608
Guy Schalnat0d580581995-07-20 02:43:20 -05001609 else
1610 truelen = 2;
1611
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001612 if (length != truelen)
Guy Schalnat0d580581995-07-20 02:43:20 -05001613 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001614 png_warning(png_ptr, "Incorrect bKGD chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001615 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001616 return;
1617 }
1618
Andreas Dilger47a0c421997-05-16 02:46:07 -05001619 png_crc_read(png_ptr, buf, truelen);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001620
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001621 if (png_crc_finish(png_ptr, 0))
1622 return;
1623
Guy Schalnate5a37791996-06-05 15:50:50 -05001624 /* We convert the index value into RGB components so that we can allow
1625 * arbitrary RGB values for background when we have transparency, and
1626 * so it is easy to determine the RGB values of the background color
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001627 * from the info_ptr struct.
1628 */
Guy Schalnat0d580581995-07-20 02:43:20 -05001629 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
Guy Schalnate5a37791996-06-05 15:50:50 -05001630 {
John Bowlercb0b2962011-05-12 21:48:29 -05001631 background.index = buf[0];
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001632
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001633 if (info_ptr && info_ptr->num_palette)
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001634 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001635 if (buf[0] >= info_ptr->num_palette)
1636 {
1637 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1638 return;
1639 }
1640
John Bowlercb0b2962011-05-12 21:48:29 -05001641 background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
1642 background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
1643 background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
Glenn Randers-Pehrson4393a9a1999-09-17 12:27:26 -05001644 }
John Bowlercb0b2962011-05-12 21:48:29 -05001645
1646 else
1647 background.red = background.green = background.blue = 0;
1648
1649 background.gray = 0;
Guy Schalnate5a37791996-06-05 15:50:50 -05001650 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001651
Andreas Dilger47a0c421997-05-16 02:46:07 -05001652 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
Guy Schalnate5a37791996-06-05 15:50:50 -05001653 {
John Bowlercb0b2962011-05-12 21:48:29 -05001654 background.index = 0;
1655 background.red =
1656 background.green =
1657 background.blue =
1658 background.gray = png_get_uint_16(buf);
Guy Schalnate5a37791996-06-05 15:50:50 -05001659 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001660
Guy Schalnat0d580581995-07-20 02:43:20 -05001661 else
1662 {
John Bowlercb0b2962011-05-12 21:48:29 -05001663 background.index = 0;
1664 background.red = png_get_uint_16(buf);
1665 background.green = png_get_uint_16(buf + 2);
1666 background.blue = png_get_uint_16(buf + 4);
1667 background.gray = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05001668 }
1669
John Bowlercb0b2962011-05-12 21:48:29 -05001670 png_set_bKGD(png_ptr, info_ptr, &background);
Guy Schalnat0d580581995-07-20 02:43:20 -05001671}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001672#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001673
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001674#ifdef PNG_READ_hIST_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001675void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001676png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001677{
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001678 unsigned int num, i;
Glenn Randers-Pehrsond1e8c862002-06-20 06:54:34 -05001679 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
Guy Schalnat0d580581995-07-20 02:43:20 -05001680
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001681 png_debug(1, "in png_handle_hIST");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001682
Guy Schalnate5a37791996-06-05 15:50:50 -05001683 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1684 png_error(png_ptr, "Missing IHDR before hIST");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001685
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001686 else if (png_ptr->mode & PNG_HAVE_IDAT)
1687 {
1688 png_warning(png_ptr, "Invalid hIST after IDAT");
1689 png_crc_finish(png_ptr, length);
1690 return;
1691 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001692
Guy Schalnate5a37791996-06-05 15:50:50 -05001693 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1694 {
1695 png_warning(png_ptr, "Missing PLTE before hIST");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001696 png_crc_finish(png_ptr, length);
1697 return;
1698 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001699
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001700 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001701 {
1702 png_warning(png_ptr, "Duplicate hIST chunk");
1703 png_crc_finish(png_ptr, length);
Guy Schalnate5a37791996-06-05 15:50:50 -05001704 return;
1705 }
1706
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -05001707 num = length / 2 ;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001708
1709 if (num != (unsigned int)png_ptr->num_palette || num >
1710 (unsigned int)PNG_MAX_PALETTE_LENGTH)
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001711 {
1712 png_warning(png_ptr, "Incorrect hIST chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001713 png_crc_finish(png_ptr, length);
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001714 return;
1715 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001716
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001717 for (i = 0; i < num; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05001718 {
1719 png_byte buf[2];
1720
1721 png_crc_read(png_ptr, buf, 2);
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001722 readbuf[i] = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001723 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001724
1725 if (png_crc_finish(png_ptr, 0))
1726 return;
1727
Glenn Randers-Pehrson76e5fd62000-12-28 07:50:05 -06001728 png_set_hIST(png_ptr, info_ptr, readbuf);
Guy Schalnat0d580581995-07-20 02:43:20 -05001729}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001730#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001731
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001732#ifdef PNG_READ_pHYs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001733void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001734png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001735{
1736 png_byte buf[9];
1737 png_uint_32 res_x, res_y;
1738 int unit_type;
1739
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001740 png_debug(1, "in png_handle_pHYs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001741
Guy Schalnate5a37791996-06-05 15:50:50 -05001742 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001743 png_error(png_ptr, "Missing IHDR before pHYs");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001744
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001745 else if (png_ptr->mode & PNG_HAVE_IDAT)
1746 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001747 png_warning(png_ptr, "Invalid pHYs after IDAT");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001748 png_crc_finish(png_ptr, length);
1749 return;
1750 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001751
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001752 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001753 {
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05001754 png_warning(png_ptr, "Duplicate pHYs chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001755 png_crc_finish(png_ptr, length);
1756 return;
1757 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001758
Guy Schalnat0d580581995-07-20 02:43:20 -05001759 if (length != 9)
1760 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001761 png_warning(png_ptr, "Incorrect pHYs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001762 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001763 return;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001764 }
Guy Schalnat0d580581995-07-20 02:43:20 -05001765
1766 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001767
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001768 if (png_crc_finish(png_ptr, 0))
1769 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001770
1771 res_x = png_get_uint_32(buf);
1772 res_y = png_get_uint_32(buf + 4);
1773 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001774 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
Guy Schalnat0d580581995-07-20 02:43:20 -05001775}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001776#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001777
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001778#ifdef PNG_READ_oFFs_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001779void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001780png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05001781{
1782 png_byte buf[9];
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001783 png_int_32 offset_x, offset_y;
Guy Schalnat0d580581995-07-20 02:43:20 -05001784 int unit_type;
1785
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001786 png_debug(1, "in png_handle_oFFs");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001787
Guy Schalnate5a37791996-06-05 15:50:50 -05001788 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1789 png_error(png_ptr, "Missing IHDR before oFFs");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001790
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001791 else if (png_ptr->mode & PNG_HAVE_IDAT)
1792 {
1793 png_warning(png_ptr, "Invalid oFFs after IDAT");
1794 png_crc_finish(png_ptr, length);
1795 return;
1796 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001797
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001798 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001799 {
1800 png_warning(png_ptr, "Duplicate oFFs chunk");
1801 png_crc_finish(png_ptr, length);
1802 return;
1803 }
Guy Schalnate5a37791996-06-05 15:50:50 -05001804
Guy Schalnat0d580581995-07-20 02:43:20 -05001805 if (length != 9)
1806 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001807 png_warning(png_ptr, "Incorrect oFFs chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001808 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05001809 return;
1810 }
1811
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06001812 png_crc_read(png_ptr, buf, 9);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001813
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06001814 if (png_crc_finish(png_ptr, 0))
1815 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05001816
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001817 offset_x = png_get_int_32(buf);
1818 offset_y = png_get_int_32(buf + 4);
Guy Schalnat0d580581995-07-20 02:43:20 -05001819 unit_type = buf[8];
Andreas Dilger47a0c421997-05-16 02:46:07 -05001820 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1821}
1822#endif
1823
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001824#ifdef PNG_READ_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001825/* Read the pCAL chunk (described in the PNG Extensions document) */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001826void /* PRIVATE */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001827png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1828{
Andreas Dilger47a0c421997-05-16 02:46:07 -05001829 png_int_32 X0, X1;
1830 png_byte type, nparams;
1831 png_charp buf, units, endptr;
1832 png_charpp params;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001833 png_size_t slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001834 int i;
1835
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001836 png_debug(1, "in png_handle_pCAL");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001837
1838 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1839 png_error(png_ptr, "Missing IHDR before pCAL");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001840
Andreas Dilger47a0c421997-05-16 02:46:07 -05001841 else if (png_ptr->mode & PNG_HAVE_IDAT)
1842 {
1843 png_warning(png_ptr, "Invalid pCAL after IDAT");
1844 png_crc_finish(png_ptr, length);
1845 return;
1846 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001847
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001848 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
Andreas Dilger47a0c421997-05-16 02:46:07 -05001849 {
1850 png_warning(png_ptr, "Duplicate pCAL chunk");
1851 png_crc_finish(png_ptr, length);
1852 return;
1853 }
1854
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001855 png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)",
1856 length + 1);
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001857 png_free(png_ptr, png_ptr->chunkdata);
1858 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001859
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001860 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001861 {
1862 png_warning(png_ptr, "No memory for pCAL purpose");
1863 return;
1864 }
1865
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06001866 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001867 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05001868
1869 if (png_crc_finish(png_ptr, 0))
1870 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001871 png_free(png_ptr, png_ptr->chunkdata);
1872 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001873 return;
1874 }
1875
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001876 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001877
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001878 png_debug(3, "Finding end of pCAL purpose string");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001879 for (buf = png_ptr->chunkdata; *buf; buf++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001880 /* Empty loop */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001881
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001882 endptr = png_ptr->chunkdata + slength;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001883
1884 /* We need to have at least 12 bytes after the purpose string
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001885 * in order to get the parameter information.
1886 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001887 if (endptr <= buf + 12)
1888 {
1889 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001890 png_free(png_ptr, png_ptr->chunkdata);
1891 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001892 return;
1893 }
1894
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001895 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001896 X0 = png_get_int_32((png_bytep)buf+1);
1897 X1 = png_get_int_32((png_bytep)buf+5);
1898 type = buf[9];
1899 nparams = buf[10];
1900 units = buf + 11;
1901
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001902 png_debug(3, "Checking pCAL equation type and number of parameters");
Andreas Dilger47a0c421997-05-16 02:46:07 -05001903 /* Check that we have the right number of parameters for known
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001904 * equation types.
1905 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05001906 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1907 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1908 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1909 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1910 {
1911 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001912 png_free(png_ptr, png_ptr->chunkdata);
1913 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001914 return;
1915 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001916
Andreas Dilger47a0c421997-05-16 02:46:07 -05001917 else if (type >= PNG_EQUATION_LAST)
1918 {
1919 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1920 }
1921
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05001922 for (buf = units; *buf; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001923 /* Empty loop to move past the units string. */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001924
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001925 png_debug(3, "Allocating pCAL parameters array");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001926
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05001927 params = (png_charpp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001928 (png_size_t)(nparams * png_sizeof(png_charp)));
1929
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05001930 if (params == NULL)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001931 {
1932 png_free(png_ptr, png_ptr->chunkdata);
1933 png_ptr->chunkdata = NULL;
1934 png_warning(png_ptr, "No memory for pCAL params");
1935 return;
1936 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05001937
1938 /* Get pointers to the start of each parameter string. */
Glenn Randers-Pehrson0f881d61998-02-07 10:20:57 -06001939 for (i = 0; i < (int)nparams; i++)
Andreas Dilger47a0c421997-05-16 02:46:07 -05001940 {
1941 buf++; /* Skip the null string terminator from previous parameter. */
1942
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001943 png_debug1(3, "Reading pCAL parameter %d", i);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001944
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001945 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
Glenn Randers-Pehrsonf9f2fe01998-03-15 18:20:23 -06001946 /* Empty loop to move past each parameter string */ ;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001947
1948 /* Make sure we haven't run out of data yet */
1949 if (buf > endptr)
1950 {
1951 png_warning(png_ptr, "Invalid pCAL data");
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001952 png_free(png_ptr, png_ptr->chunkdata);
1953 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001954 png_free(png_ptr, params);
1955 return;
1956 }
1957 }
1958
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001959 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
Andreas Dilger47a0c421997-05-16 02:46:07 -05001960 units, params);
1961
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001962 png_free(png_ptr, png_ptr->chunkdata);
1963 png_ptr->chunkdata = NULL;
Andreas Dilger47a0c421997-05-16 02:46:07 -05001964 png_free(png_ptr, params);
Guy Schalnat0d580581995-07-20 02:43:20 -05001965}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05001966#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05001967
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05001968#ifdef PNG_READ_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05001969/* Read the sCAL chunk */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05001970void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001971png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1972{
John Bowler168a4332011-01-16 19:32:22 -06001973 png_size_t slength, i;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001974 int state;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001975
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05001976 png_debug(1, "in png_handle_sCAL");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001977
1978 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1979 png_error(png_ptr, "Missing IHDR before sCAL");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001980
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001981 else if (png_ptr->mode & PNG_HAVE_IDAT)
1982 {
1983 png_warning(png_ptr, "Invalid sCAL after IDAT");
1984 png_crc_finish(png_ptr, length);
1985 return;
1986 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001987
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06001988 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06001989 {
1990 png_warning(png_ptr, "Duplicate sCAL chunk");
1991 png_crc_finish(png_ptr, length);
1992 return;
1993 }
1994
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001995 png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05001996 length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001997
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05001998 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06001999
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05002000 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002001 {
2002 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002003 png_crc_finish(png_ptr, length);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002004 return;
2005 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002006
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002007 slength = (png_size_t)length;
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05002008 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002009 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002010
2011 if (png_crc_finish(png_ptr, 0))
2012 {
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05002013 png_free(png_ptr, png_ptr->chunkdata);
2014 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002015 return;
2016 }
2017
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002018 /* Validate the unit. */
2019 if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2)
Glenn Randers-Pehrson4accabb2000-04-14 14:20:47 -05002020 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002021 png_warning(png_ptr, "Invalid sCAL ignored: invalid unit");
Glenn Randers-Pehrsonef3831a2010-06-22 13:03:32 -05002022 png_free(png_ptr, png_ptr->chunkdata);
2023 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002024 return;
2025 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -05002026
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002027 /* Validate the ASCII numbers, need two ASCII numbers separated by
2028 * a '\0' and they need to fit exactly in the chunk data.
2029 */
John Bowler168a4332011-01-16 19:32:22 -06002030 i = 0;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002031 state = 0;
Glenn Randers-Pehrsonccadcae2010-10-23 17:29:13 -05002032
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002033 if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
John Bowler168a4332011-01-16 19:32:22 -06002034 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
2035 i >= slength || png_ptr->chunkdata[i++] != 0)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002036 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
2037
2038 else
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -06002039 {
John Bowler168a4332011-01-16 19:32:22 -06002040 png_size_t heighti = i;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002041
John Bowler168a4332011-01-16 19:32:22 -06002042 if (png_ptr->chunkdata[i] == 45 /* negative height */ ||
2043 !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
2044 i != slength)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002045 png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
2046
2047 else
2048 /* This is the (only) success case. */
2049 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
2050 png_ptr->chunkdata+1, png_ptr->chunkdata+heighti);
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002051 }
2052
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002053 /* Clean up - just free the temporarily allocated buffer. */
Glenn Randers-Pehrsond8d7b942008-07-21 10:34:34 -05002054 png_free(png_ptr, png_ptr->chunkdata);
2055 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002056}
2057#endif
2058
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002059#ifdef PNG_READ_tIME_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002060void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002061png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002062{
2063 png_byte buf[7];
2064 png_time mod_time;
2065
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002066 png_debug(1, "in png_handle_tIME");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002067
Guy Schalnate5a37791996-06-05 15:50:50 -05002068 if (!(png_ptr->mode & PNG_HAVE_IHDR))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002069 png_error(png_ptr, "Out of place tIME chunk");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002070
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002071 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002072 {
2073 png_warning(png_ptr, "Duplicate tIME chunk");
2074 png_crc_finish(png_ptr, length);
2075 return;
2076 }
2077
2078 if (png_ptr->mode & PNG_HAVE_IDAT)
2079 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnate5a37791996-06-05 15:50:50 -05002080
Guy Schalnat0d580581995-07-20 02:43:20 -05002081 if (length != 7)
2082 {
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002083 png_warning(png_ptr, "Incorrect tIME chunk length");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002084 png_crc_finish(png_ptr, length);
Guy Schalnat0d580581995-07-20 02:43:20 -05002085 return;
2086 }
2087
2088 png_crc_read(png_ptr, buf, 7);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002089
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002090 if (png_crc_finish(png_ptr, 0))
2091 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002092
2093 mod_time.second = buf[6];
2094 mod_time.minute = buf[5];
2095 mod_time.hour = buf[4];
2096 mod_time.day = buf[3];
2097 mod_time.month = buf[2];
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002098 mod_time.year = png_get_uint_16(buf);
Guy Schalnat0d580581995-07-20 02:43:20 -05002099
Andreas Dilger47a0c421997-05-16 02:46:07 -05002100 png_set_tIME(png_ptr, info_ptr, &mod_time);
Guy Schalnat0d580581995-07-20 02:43:20 -05002101}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002102#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002103
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002104#ifdef PNG_READ_tEXt_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002105/* Note: this does not properly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002106void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002107png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002108{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002109 png_textp text_ptr;
Guy Schalnatb2e01bd1996-01-26 01:38:47 -06002110 png_charp key;
Guy Schalnat6d764711995-12-19 03:22:19 -06002111 png_charp text;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002112 png_uint_32 skip = 0;
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002113 png_size_t slength;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002114 int ret;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002115
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002116 png_debug(1, "in png_handle_tEXt");
Guy Schalnat0d580581995-07-20 02:43:20 -05002117
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002118#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002119 if (png_ptr->user_chunk_cache_max != 0)
2120 {
2121 if (png_ptr->user_chunk_cache_max == 1)
2122 {
2123 png_crc_finish(png_ptr, length);
2124 return;
2125 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002126
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002127 if (--png_ptr->user_chunk_cache_max == 1)
2128 {
2129 png_warning(png_ptr, "No space in chunk cache for tEXt");
2130 png_crc_finish(png_ptr, length);
2131 return;
2132 }
2133 }
2134#endif
2135
Guy Schalnate5a37791996-06-05 15:50:50 -05002136 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2137 png_error(png_ptr, "Missing IHDR before tEXt");
2138
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002139 if (png_ptr->mode & PNG_HAVE_IDAT)
2140 png_ptr->mode |= PNG_AFTER_IDAT;
2141
Andreas Dilger47a0c421997-05-16 02:46:07 -05002142#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002143 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002144 {
2145 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002146 skip = length - (png_uint_32)65535L;
2147 length = (png_uint_32)65535L;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002148 }
2149#endif
2150
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002151 png_free(png_ptr, png_ptr->chunkdata);
2152
2153 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002154
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002155 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002156 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05002157 png_warning(png_ptr, "No memory to process text chunk");
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002158 return;
2159 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002160
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002161 slength = (png_size_t)length;
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002162 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002163
2164 if (png_crc_finish(png_ptr, skip))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002165 {
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002166 png_free(png_ptr, png_ptr->chunkdata);
2167 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002168 return;
2169 }
2170
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002171 key = png_ptr->chunkdata;
2172
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002173 key[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002174
2175 for (text = key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002176 /* Empty loop to find end of key */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002177
Glenn Randers-Pehrsona357b991998-02-08 20:56:40 -06002178 if (text != key + slength)
Guy Schalnat0d580581995-07-20 02:43:20 -05002179 text++;
2180
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002181 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002182 png_sizeof(png_text));
2183
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002184 if (text_ptr == NULL)
2185 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002186 png_warning(png_ptr, "Not enough memory to process text chunk");
2187 png_free(png_ptr, png_ptr->chunkdata);
2188 png_ptr->chunkdata = NULL;
2189 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002190 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002191
Andreas Dilger47a0c421997-05-16 02:46:07 -05002192 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2193 text_ptr->key = key;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002194 text_ptr->lang = NULL;
2195 text_ptr->lang_key = NULL;
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002196 text_ptr->itxt_length = 0;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002197 text_ptr->text = text;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002198 text_ptr->text_length = png_strlen(text);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002199
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002200 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002201
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002202 png_free(png_ptr, png_ptr->chunkdata);
2203 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002204 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002205
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002206 if (ret)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002207 png_warning(png_ptr, "Insufficient memory to process text chunk");
Guy Schalnat0d580581995-07-20 02:43:20 -05002208}
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002209#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002210
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002211#ifdef PNG_READ_zTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002212/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002213void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002214png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
Guy Schalnat0d580581995-07-20 02:43:20 -05002215{
Andreas Dilger47a0c421997-05-16 02:46:07 -05002216 png_textp text_ptr;
Guy Schalnat6d764711995-12-19 03:22:19 -06002217 png_charp text;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002218 int comp_type;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002219 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002220 png_size_t slength, prefix_len, data_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002221
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002222 png_debug(1, "in png_handle_zTXt");
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002223
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002224#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002225 if (png_ptr->user_chunk_cache_max != 0)
2226 {
2227 if (png_ptr->user_chunk_cache_max == 1)
2228 {
2229 png_crc_finish(png_ptr, length);
2230 return;
2231 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002232
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002233 if (--png_ptr->user_chunk_cache_max == 1)
2234 {
2235 png_warning(png_ptr, "No space in chunk cache for zTXt");
2236 png_crc_finish(png_ptr, length);
2237 return;
2238 }
2239 }
2240#endif
2241
Guy Schalnate5a37791996-06-05 15:50:50 -05002242 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2243 png_error(png_ptr, "Missing IHDR before zTXt");
2244
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002245 if (png_ptr->mode & PNG_HAVE_IDAT)
2246 png_ptr->mode |= PNG_AFTER_IDAT;
2247
Andreas Dilger47a0c421997-05-16 02:46:07 -05002248#ifdef PNG_MAX_MALLOC_64K
2249 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002250 * there is no hard and fast rule to tell us where to stop.
2251 */
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002252 if (length > (png_uint_32)65535L)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002253 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002254 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
2255 png_crc_finish(png_ptr, length);
2256 return;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002257 }
2258#endif
2259
Glenn Randers-Pehrson97a9b482008-10-25 20:03:28 -05002260 png_free(png_ptr, png_ptr->chunkdata);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002261 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002262
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002263 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002264 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002265 png_warning(png_ptr, "Out of memory processing zTXt chunk");
2266 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002267 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002268
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002269 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002270 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002271
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002272 if (png_crc_finish(png_ptr, 0))
2273 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002274 png_free(png_ptr, png_ptr->chunkdata);
2275 png_ptr->chunkdata = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002276 return;
2277 }
2278
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002279 png_ptr->chunkdata[slength] = 0x00;
Guy Schalnat0d580581995-07-20 02:43:20 -05002280
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002281 for (text = png_ptr->chunkdata; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002282 /* Empty loop */ ;
Guy Schalnat0d580581995-07-20 02:43:20 -05002283
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002284 /* zTXt must have some text after the chunkdataword */
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002285 if (text >= png_ptr->chunkdata + slength - 2)
Guy Schalnat0d580581995-07-20 02:43:20 -05002286 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002287 png_warning(png_ptr, "Truncated zTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002288 png_free(png_ptr, png_ptr->chunkdata);
2289 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002290 return;
Guy Schalnat0d580581995-07-20 02:43:20 -05002291 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002292
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002293 else
Guy Schalnat0d580581995-07-20 02:43:20 -05002294 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002295 comp_type = *(++text);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002296
Glenn Randers-Pehrsonf05f8032000-12-23 14:27:39 -06002297 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2298 {
2299 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2300 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2301 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002302
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002303 text++; /* Skip the compression_method byte */
Guy Schalnat0d580581995-07-20 02:43:20 -05002304 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002305
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002306 prefix_len = text - png_ptr->chunkdata;
Guy Schalnat0d580581995-07-20 02:43:20 -05002307
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -05002308 png_decompress_chunk(png_ptr, comp_type,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002309 (png_size_t)length, prefix_len, &data_len);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002310
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002311 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002312 png_sizeof(png_text));
2313
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002314 if (text_ptr == NULL)
2315 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002316 png_warning(png_ptr, "Not enough memory to process zTXt chunk");
2317 png_free(png_ptr, png_ptr->chunkdata);
2318 png_ptr->chunkdata = NULL;
2319 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002320 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002321
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002322 text_ptr->compression = comp_type;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002323 text_ptr->key = png_ptr->chunkdata;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002324 text_ptr->lang = NULL;
2325 text_ptr->lang_key = NULL;
2326 text_ptr->itxt_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002327 text_ptr->text = png_ptr->chunkdata + prefix_len;
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002328 text_ptr->text_length = data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002329
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002330 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002331
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002332 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002333 png_free(png_ptr, png_ptr->chunkdata);
2334 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002335
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002336 if (ret)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002337 png_error(png_ptr, "Insufficient memory to store zTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002338}
2339#endif
2340
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002341#ifdef PNG_READ_iTXt_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002342/* Note: this does not correctly handle chunks that are > 64K under DOS */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002343void /* PRIVATE */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002344png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2345{
2346 png_textp text_ptr;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002347 png_charp key, lang, text, lang_key;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -06002348 int comp_flag;
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002349 int comp_type = 0;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002350 int ret;
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002351 png_size_t slength, prefix_len, data_len;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002352
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002353 png_debug(1, "in png_handle_iTXt");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002354
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002355#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002356 if (png_ptr->user_chunk_cache_max != 0)
2357 {
2358 if (png_ptr->user_chunk_cache_max == 1)
2359 {
2360 png_crc_finish(png_ptr, length);
2361 return;
2362 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002363
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002364 if (--png_ptr->user_chunk_cache_max == 1)
2365 {
2366 png_warning(png_ptr, "No space in chunk cache for iTXt");
2367 png_crc_finish(png_ptr, length);
2368 return;
2369 }
2370 }
2371#endif
2372
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002373 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2374 png_error(png_ptr, "Missing IHDR before iTXt");
2375
2376 if (png_ptr->mode & PNG_HAVE_IDAT)
2377 png_ptr->mode |= PNG_AFTER_IDAT;
2378
2379#ifdef PNG_MAX_MALLOC_64K
2380 /* We will no doubt have problems with chunks even half this size, but
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002381 * there is no hard and fast rule to tell us where to stop.
2382 */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002383 if (length > (png_uint_32)65535L)
2384 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002385 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
2386 png_crc_finish(png_ptr, length);
2387 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002388 }
2389#endif
2390
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002391 png_free(png_ptr, png_ptr->chunkdata);
2392 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002393
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002394 if (png_ptr->chunkdata == NULL)
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002395 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002396 png_warning(png_ptr, "No memory to process iTXt chunk");
2397 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002398 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002399
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002400 slength = (png_size_t)length;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002401 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002402
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002403 if (png_crc_finish(png_ptr, 0))
2404 {
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002405 png_free(png_ptr, png_ptr->chunkdata);
2406 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002407 return;
2408 }
2409
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002410 png_ptr->chunkdata[slength] = 0x00;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002411
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002412 for (lang = png_ptr->chunkdata; *lang; lang++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002413 /* Empty loop */ ;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002414
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002415 lang++; /* Skip NUL separator */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002416
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002417 /* iTXt must have a language tag (possibly empty), two compression bytes,
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002418 * translated keyword (possibly empty), and possibly some text after the
2419 * keyword
2420 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002421
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002422 if (lang >= png_ptr->chunkdata + slength - 3)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002423 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002424 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002425 png_free(png_ptr, png_ptr->chunkdata);
2426 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002427 return;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002428 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002429
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002430 else
2431 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002432 comp_flag = *lang++;
2433 comp_type = *lang++;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002434 }
2435
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002436 for (lang_key = lang; *lang_key; lang_key++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002437 /* Empty loop */ ;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002438
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002439 lang_key++; /* Skip NUL separator */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002440
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002441 if (lang_key >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002442 {
2443 png_warning(png_ptr, "Truncated iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002444 png_free(png_ptr, png_ptr->chunkdata);
2445 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002446 return;
2447 }
2448
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002449 for (text = lang_key; *text; text++)
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002450 /* Empty loop */ ;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002451
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002452 text++; /* Skip NUL separator */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002453
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002454 if (text >= png_ptr->chunkdata + slength)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002455 {
2456 png_warning(png_ptr, "Malformed iTXt chunk");
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002457 png_free(png_ptr, png_ptr->chunkdata);
2458 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002459 return;
2460 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002461
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002462 prefix_len = text - png_ptr->chunkdata;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002463
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002464 key=png_ptr->chunkdata;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002465
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002466 if (comp_flag)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002467 png_decompress_chunk(png_ptr, comp_type,
2468 (size_t)length, prefix_len, &data_len);
2469
Glenn Randers-Pehrson68ea2432000-04-01 21:10:05 -06002470 else
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002471 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
2472
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002473 text_ptr = (png_textp)png_malloc_warn(png_ptr,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002474 png_sizeof(png_text));
2475
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002476 if (text_ptr == NULL)
2477 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002478 png_warning(png_ptr, "Not enough memory to process iTXt chunk");
2479 png_free(png_ptr, png_ptr->chunkdata);
2480 png_ptr->chunkdata = NULL;
2481 return;
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002482 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002483
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002484 text_ptr->compression = (int)comp_flag + 1;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002485 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2486 text_ptr->lang = png_ptr->chunkdata + (lang - key);
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002487 text_ptr->itxt_length = data_len;
2488 text_ptr->text_length = 0;
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002489 text_ptr->key = png_ptr->chunkdata;
2490 text_ptr->text = png_ptr->chunkdata + prefix_len;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002491
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002492 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05002493
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -05002494 png_free(png_ptr, text_ptr);
Glenn Randers-Pehrsonb3ff9682008-07-21 08:05:57 -05002495 png_free(png_ptr, png_ptr->chunkdata);
2496 png_ptr->chunkdata = NULL;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002497
Glenn Randers-Pehrson07748d12002-05-25 11:12:10 -05002498 if (ret)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002499 png_error(png_ptr, "Insufficient memory to store iTXt chunk");
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002500}
2501#endif
2502
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002503/* This function is called when we haven't found a handler for a
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002504 * chunk. If there isn't a problem with the chunk itself (ie bad
2505 * chunk name, CRC, or a critical chunk), the chunk is silently ignored
2506 * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2507 * case it will be saved away to be written out later.
2508 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002509void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002510png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2511{
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002512 png_uint_32 skip = 0;
2513
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002514 png_debug(1, "in png_handle_unknown");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002515
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06002516#ifdef PNG_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002517 if (png_ptr->user_chunk_cache_max != 0)
2518 {
2519 if (png_ptr->user_chunk_cache_max == 1)
2520 {
2521 png_crc_finish(png_ptr, length);
2522 return;
2523 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002524
Glenn Randers-Pehrson800d1e92008-08-20 17:25:21 -05002525 if (--png_ptr->user_chunk_cache_max == 1)
2526 {
2527 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2528 png_crc_finish(png_ptr, length);
2529 return;
2530 }
2531 }
2532#endif
2533
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002534 if (png_ptr->mode & PNG_HAVE_IDAT)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002535 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002536 PNG_IDAT;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002537
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002538 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002539 png_ptr->mode |= PNG_AFTER_IDAT;
2540 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002541
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002542 if (!(png_ptr->chunk_name[0] & 0x20))
2543 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002544#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002545 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002546 PNG_HANDLE_CHUNK_ALWAYS
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002547#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002548 && png_ptr->read_user_chunk_fn == NULL
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002549#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002550 )
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05002551#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002552 png_chunk_error(png_ptr, "unknown critical chunk");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002553 }
2554
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002555#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002556 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002557#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002558 || (png_ptr->read_user_chunk_fn != NULL)
2559#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002560 )
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002561 {
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002562#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002563 if (length > (png_uint_32)65535L)
2564 {
2565 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2566 skip = length - (png_uint_32)65535L;
2567 length = (png_uint_32)65535L;
2568 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002569#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002570
2571 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
2572 (png_charp)png_ptr->chunk_name,
2573 png_sizeof(png_ptr->unknown_chunk.name));
2574
2575 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2576 = '\0';
2577
2578 png_ptr->unknown_chunk.size = (png_size_t)length;
2579
2580 if (length == 0)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002581 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002582
2583 else
2584 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002585 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2586 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002587 }
2588
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002589#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002590 if (png_ptr->read_user_chunk_fn != NULL)
2591 {
2592 /* Callback to user unknown chunk handler */
2593 int ret;
2594
2595 ret = (*(png_ptr->read_user_chunk_fn))
2596 (png_ptr, &png_ptr->unknown_chunk);
2597
2598 if (ret < 0)
2599 png_chunk_error(png_ptr, "error in user chunk");
2600
2601 if (ret == 0)
2602 {
2603 if (!(png_ptr->chunk_name[0] & 0x20))
2604 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002605#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002606 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
2607 PNG_HANDLE_CHUNK_ALWAYS)
Glenn Randers-Pehrson7824a702009-06-13 10:05:05 -05002608#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002609 png_chunk_error(png_ptr, "unknown critical chunk");
2610 }
2611
2612 png_set_unknown_chunks(png_ptr, info_ptr,
2613 &png_ptr->unknown_chunk, 1);
2614 }
2615 }
2616
2617 else
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002618#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002619 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2620
2621 png_free(png_ptr, png_ptr->unknown_chunk.data);
2622 png_ptr->unknown_chunk.data = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002623 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002624
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002625 else
2626#endif
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002627 skip = length;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002628
2629 png_crc_finish(png_ptr, skip);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002630
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05002631#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002632 PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -06002633#endif
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002634}
2635
2636/* This function is called to verify that a chunk name is valid.
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002637 * This function can't have the "critical chunk check" incorporated
2638 * into it, since in the future we will need to be able to call user
2639 * functions to handle unknown critical chunks after we check that
2640 * the chunk name itself is valid.
2641 */
Andreas Dilger47a0c421997-05-16 02:46:07 -05002642
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -05002643#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
Andreas Dilger47a0c421997-05-16 02:46:07 -05002644
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002645void /* PRIVATE */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002646png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002647{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002648 png_debug(1, "in png_check_chunk_name");
Andreas Dilger47a0c421997-05-16 02:46:07 -05002649 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
Glenn Randers-Pehrsoneb580912008-07-30 14:47:09 -05002650 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002651 {
Glenn Randers-Pehrson70e3f541998-01-03 22:40:55 -06002652 png_chunk_error(png_ptr, "invalid chunk type");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06002653 }
2654}
2655
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05002656/* Combines the row recently read in with the existing pixels in the
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002657 * row. This routine takes care of alpha and transparency if requested.
2658 * This routine also handles the two methods of progressive display
2659 * of interlaced images, depending on the mask value.
2660 * The mask value describes which pixels are to be combined with
2661 * the row. The pattern always repeats every 8 pixels, so just 8
2662 * bits are needed. A one indicates the pixel is to be combined,
2663 * a zero indicates the pixel is to be skipped. This is in addition
2664 * to any alpha or transparency value associated with the pixel. If
2665 * you want all pixels to be combined, pass 0xff (255) in mask.
2666 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002667
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002668void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002669png_combine_row(png_structp png_ptr, png_bytep row, int mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002670{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002671 png_debug(1, "in png_combine_row");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002672
John Bowler9994f252011-05-15 18:52:39 -05002673 /* Added in 1.5.3: the row_info should match the information returned by any
2674 * call to png_read_update_info at this point. Do not continue if we got
2675 * this wrong.
2676 */
2677 if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=
2678 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width))
2679 png_error(png_ptr, "internal row size calculation error");
2680
Guy Schalnat0d580581995-07-20 02:43:20 -05002681 if (mask == 0xff)
2682 {
Guy Schalnat51f0eb41995-09-26 05:22:39 -05002683 png_memcpy(row, png_ptr->row_buf + 1,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002684 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
Guy Schalnat0d580581995-07-20 02:43:20 -05002685 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002686
Guy Schalnat0d580581995-07-20 02:43:20 -05002687 else
2688 {
2689 switch (png_ptr->row_info.pixel_depth)
2690 {
2691 case 1:
2692 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002693 png_bytep sp = png_ptr->row_buf + 1;
2694 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002695 int s_inc, s_start, s_end;
2696 int m = 0x80;
2697 int shift;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002698 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002699 png_uint_32 row_width = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05002700
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002701#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002702 if (png_ptr->transformations & PNG_PACKSWAP)
Andreas Dilger47a0c421997-05-16 02:46:07 -05002703 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002704 s_start = 0;
2705 s_end = 7;
2706 s_inc = 1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002707 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002708
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002709 else
2710#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002711 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002712 s_start = 7;
2713 s_end = 0;
2714 s_inc = -1;
2715 }
2716
2717 shift = s_start;
2718
2719 for (i = 0; i < row_width; i++)
2720 {
2721 if (m & mask)
2722 {
2723 int value;
2724
2725 value = (*sp >> shift) & 0x01;
2726 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2727 *dp |= (png_byte)(value << shift);
2728 }
2729
2730 if (shift == s_end)
2731 {
2732 shift = s_start;
2733 sp++;
2734 dp++;
2735 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002736
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002737 else
2738 shift += s_inc;
2739
2740 if (m == 1)
2741 m = 0x80;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002742
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002743 else
2744 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002745 }
2746 break;
2747 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002748
Guy Schalnat0d580581995-07-20 02:43:20 -05002749 case 2:
2750 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002751 png_bytep sp = png_ptr->row_buf + 1;
2752 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002753 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002754 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002755 int shift;
2756 png_uint_32 i;
2757 png_uint_32 row_width = png_ptr->width;
2758 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002759
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002760#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002761 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002762 {
2763 s_start = 0;
2764 s_end = 6;
2765 s_inc = 2;
2766 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002767
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002768 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002769#endif
2770 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002771 s_start = 6;
2772 s_end = 0;
2773 s_inc = -2;
2774 }
2775
2776 shift = s_start;
2777
2778 for (i = 0; i < row_width; i++)
2779 {
2780 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002781 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002782 value = (*sp >> shift) & 0x03;
2783 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2784 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002785 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002786
2787 if (shift == s_end)
2788 {
2789 shift = s_start;
2790 sp++;
2791 dp++;
2792 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002793
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002794 else
2795 shift += s_inc;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002796
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002797 if (m == 1)
2798 m = 0x80;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002799
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002800 else
2801 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002802 }
2803 break;
2804 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002805
Guy Schalnat0d580581995-07-20 02:43:20 -05002806 case 4:
2807 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002808 png_bytep sp = png_ptr->row_buf + 1;
2809 png_bytep dp = row;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002810 int s_start, s_end, s_inc;
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002811 int m = 0x80;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002812 int shift;
2813 png_uint_32 i;
2814 png_uint_32 row_width = png_ptr->width;
2815 int value;
Guy Schalnat0d580581995-07-20 02:43:20 -05002816
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002817#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002818 if (png_ptr->transformations & PNG_PACKSWAP)
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002819 {
2820 s_start = 0;
2821 s_end = 4;
2822 s_inc = 4;
2823 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002824
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002825 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002826#endif
2827 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002828 s_start = 4;
2829 s_end = 0;
2830 s_inc = -4;
2831 }
2832 shift = s_start;
2833
2834 for (i = 0; i < row_width; i++)
2835 {
2836 if (m & mask)
Guy Schalnat0d580581995-07-20 02:43:20 -05002837 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002838 value = (*sp >> shift) & 0xf;
2839 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2840 *dp |= (png_byte)(value << shift);
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002841 }
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002842
2843 if (shift == s_end)
2844 {
2845 shift = s_start;
2846 sp++;
2847 dp++;
2848 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002849
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002850 else
2851 shift += s_inc;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002852
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002853 if (m == 1)
2854 m = 0x80;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002855
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002856 else
2857 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002858 }
2859 break;
2860 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002861
Guy Schalnat0d580581995-07-20 02:43:20 -05002862 default:
2863 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002864 png_bytep sp = png_ptr->row_buf + 1;
2865 png_bytep dp = row;
2866 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2867 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002868 png_uint_32 row_width = png_ptr->width;
2869 png_byte m = 0x80;
Guy Schalnat0d580581995-07-20 02:43:20 -05002870
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002871 for (i = 0; i < row_width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002872 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002873 if (m & mask)
2874 {
2875 png_memcpy(dp, sp, pixel_bytes);
2876 }
2877
2878 sp += pixel_bytes;
2879 dp += pixel_bytes;
2880
2881 if (m == 1)
2882 m = 0x80;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002883
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002884 else
2885 m >>= 1;
Guy Schalnat0d580581995-07-20 02:43:20 -05002886 }
2887 break;
2888 }
2889 }
2890 }
2891}
2892
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002893#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05002894void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002895png_do_read_interlace(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05002896{
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06002897 png_row_infop row_info = &(png_ptr->row_info);
2898 png_bytep row = png_ptr->row_buf + 1;
2899 int pass = png_ptr->pass;
2900 png_uint_32 transformations = png_ptr->transformations;
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05002901 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2902 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05002903 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06002904
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05002905 png_debug(1, "in png_do_read_interlace");
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002906 if (row != NULL && row_info != NULL)
Guy Schalnat0d580581995-07-20 02:43:20 -05002907 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002908 png_uint_32 final_width;
2909
2910 final_width = row_info->width * png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05002911
2912 switch (row_info->pixel_depth)
2913 {
2914 case 1:
2915 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05002916 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2917 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002918 int sshift, dshift;
2919 int s_start, s_end, s_inc;
2920 int jstop = png_pass_inc[pass];
2921 png_byte v;
Guy Schalnat0d580581995-07-20 02:43:20 -05002922 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002923 int j;
Guy Schalnat0d580581995-07-20 02:43:20 -05002924
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002925#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002926 if (transformations & PNG_PACKSWAP)
2927 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002928 sshift = (int)((row_info->width + 7) & 0x07);
2929 dshift = (int)((final_width + 7) & 0x07);
2930 s_start = 7;
2931 s_end = 0;
2932 s_inc = -1;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002933 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002934
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002935 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002936#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002937 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002938 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2939 dshift = 7 - (int)((final_width + 7) & 0x07);
2940 s_start = 0;
2941 s_end = 7;
2942 s_inc = 1;
2943 }
Glenn Randers-Pehrson5dd2b8e2004-11-24 07:50:16 -06002944
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002945 for (i = 0; i < row_info->width; i++)
2946 {
2947 v = (png_byte)((*sp >> sshift) & 0x01);
2948 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05002949 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002950 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2951 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002952
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002953 if (dshift == s_end)
2954 {
2955 dshift = s_start;
2956 dp--;
2957 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002958
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002959 else
2960 dshift += s_inc;
2961 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002962
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002963 if (sshift == s_end)
2964 {
2965 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05002966 sp--;
2967 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002968
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002969 else
2970 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05002971 }
2972 break;
2973 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002974
Guy Schalnat0d580581995-07-20 02:43:20 -05002975 case 2:
2976 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002977 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2978 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2979 int sshift, dshift;
2980 int s_start, s_end, s_inc;
2981 int jstop = png_pass_inc[pass];
Andreas Dilger47a0c421997-05-16 02:46:07 -05002982 png_uint_32 i;
Guy Schalnat0d580581995-07-20 02:43:20 -05002983
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05002984#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05002985 if (transformations & PNG_PACKSWAP)
2986 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002987 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2988 dshift = (int)(((final_width + 3) & 0x03) << 1);
2989 s_start = 6;
2990 s_end = 0;
2991 s_inc = -2;
Andreas Dilger47a0c421997-05-16 02:46:07 -05002992 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06002993
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002994 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05002995#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05002996 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06002997 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2998 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2999 s_start = 0;
3000 s_end = 6;
3001 s_inc = 2;
3002 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003003
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003004 for (i = 0; i < row_info->width; i++)
3005 {
3006 png_byte v;
3007 int j;
3008
3009 v = (png_byte)((*sp >> sshift) & 0x03);
3010 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003011 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003012 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
3013 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003014
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003015 if (dshift == s_end)
3016 {
3017 dshift = s_start;
3018 dp--;
3019 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003020
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003021 else
3022 dshift += s_inc;
3023 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003024
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003025 if (sshift == s_end)
3026 {
3027 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05003028 sp--;
3029 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003030
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003031 else
3032 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003033 }
3034 break;
3035 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003036
Guy Schalnat0d580581995-07-20 02:43:20 -05003037 case 4:
3038 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003039 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
3040 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003041 int sshift, dshift;
3042 int s_start, s_end, s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003043 png_uint_32 i;
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003044 int jstop = png_pass_inc[pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003045
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003046#ifdef PNG_READ_PACKSWAP_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -05003047 if (transformations & PNG_PACKSWAP)
3048 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003049 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
3050 dshift = (int)(((final_width + 1) & 0x01) << 2);
3051 s_start = 4;
3052 s_end = 0;
3053 s_inc = -4;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003054 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003055
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003056 else
Andreas Dilger47a0c421997-05-16 02:46:07 -05003057#endif
3058 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003059 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
3060 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
3061 s_start = 0;
3062 s_end = 4;
3063 s_inc = 4;
3064 }
Andreas Dilger47a0c421997-05-16 02:46:07 -05003065
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003066 for (i = 0; i < row_info->width; i++)
3067 {
3068 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
3069 int j;
Andreas Dilger47a0c421997-05-16 02:46:07 -05003070
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003071 for (j = 0; j < jstop; j++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003072 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003073 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
3074 *dp |= (png_byte)(v << dshift);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003075
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003076 if (dshift == s_end)
3077 {
3078 dshift = s_start;
3079 dp--;
3080 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003081
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003082 else
3083 dshift += s_inc;
3084 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003085
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003086 if (sshift == s_end)
3087 {
3088 sshift = s_start;
Guy Schalnat0d580581995-07-20 02:43:20 -05003089 sp--;
3090 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003091
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003092 else
3093 sshift += s_inc;
Guy Schalnat0d580581995-07-20 02:43:20 -05003094 }
3095 break;
3096 }
3097 default:
3098 {
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003099 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003100
Glenn Randers-Pehrsone3f3c4e2010-02-07 18:08:50 -06003101 png_bytep sp = row + (png_size_t)(row_info->width - 1)
3102 * pixel_bytes;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003103
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003104 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003105
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003106 int jstop = png_pass_inc[pass];
3107 png_uint_32 i;
3108
3109 for (i = 0; i < row_info->width; i++)
Guy Schalnat0d580581995-07-20 02:43:20 -05003110 {
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003111 png_byte v[8];
3112 int j;
3113
3114 png_memcpy(v, sp, pixel_bytes);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003115
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003116 for (j = 0; j < jstop; j++)
3117 {
3118 png_memcpy(dp, v, pixel_bytes);
3119 dp -= pixel_bytes;
3120 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003121
Glenn Randers-Pehrsonc3dda6d2004-11-27 18:22:29 -06003122 sp -= pixel_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003123 }
3124 break;
3125 }
3126 }
3127 row_info->width = final_width;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003128 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
Guy Schalnat0d580581995-07-20 02:43:20 -05003129 }
Glenn Randers-Pehrsonb2aca212009-09-23 11:32:37 -05003130#ifndef PNG_READ_PACKSWAP_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003131 PNG_UNUSED(transformations) /* Silence compiler warning */
Glenn Randers-Pehrson104622b2000-05-29 08:58:03 -05003132#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003133}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003134#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003135
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003136void /* PRIVATE */
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -06003137png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003138 png_const_bytep prev_row, int filter)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003139{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003140 png_debug(1, "in png_read_filter_row");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003141 png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003142 switch (filter)
3143 {
3144 case PNG_FILTER_VALUE_NONE:
3145 break;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003146
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003147 case PNG_FILTER_VALUE_SUB:
3148 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003149 png_size_t i;
3150 png_size_t istop = row_info->rowbytes;
3151 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003152 png_bytep rp = row + bpp;
3153 png_bytep lp = row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003154
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003155 for (i = bpp; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003156 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003157 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
3158 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003159 }
3160 break;
3161 }
3162 case PNG_FILTER_VALUE_UP:
3163 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003164 png_size_t i;
3165 png_size_t istop = row_info->rowbytes;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003166 png_bytep rp = row;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003167 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003168
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003169 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003170 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003171 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3172 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003173 }
3174 break;
3175 }
3176 case PNG_FILTER_VALUE_AVG:
3177 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003178 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003179 png_bytep rp = row;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003180 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003181 png_bytep lp = row;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003182 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3183 png_size_t istop = row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003184
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003185 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003186 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003187 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003188 ((int)(*pp++) / 2 )) & 0xff);
3189
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003190 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003191 }
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003192
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003193 for (i = 0; i < istop; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003194 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003195 *rp = (png_byte)(((int)(*rp) +
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003196 (int)(*pp++ + *lp++) / 2 ) & 0xff);
3197
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003198 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003199 }
3200 break;
3201 }
3202 case PNG_FILTER_VALUE_PAETH:
3203 {
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003204 png_size_t i;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003205 png_bytep rp = row;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003206 png_const_bytep pp = prev_row;
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003207 png_bytep lp = row;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003208 png_const_bytep cp = prev_row;
3209 unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
3210 png_size_t istop=row_info->rowbytes - bpp;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003211
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003212 for (i = 0; i < bpp; i++)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003213 {
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003214 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3215 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003216 }
3217
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003218 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003219 {
3220 int a, b, c, pa, pb, pc, p;
3221
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003222 a = *lp++;
3223 b = *pp++;
3224 c = *cp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003225
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003226 p = b - c;
3227 pc = a - c;
3228
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003229#ifdef PNG_USE_ABS
Glenn Randers-Pehrson1d963611998-05-02 12:52:25 -05003230 pa = abs(p);
3231 pb = abs(pc);
3232 pc = abs(p + pc);
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003233#else
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003234 pa = p < 0 ? -p : p;
3235 pb = pc < 0 ? -pc : pc;
3236 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003237#endif
3238
3239 /*
3240 if (pa <= pb && pa <= pc)
3241 p = a;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003242
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003243 else if (pb <= pc)
3244 p = b;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003245
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003246 else
3247 p = c;
3248 */
3249
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003250 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003251
Glenn Randers-Pehrson8686fff1998-05-21 09:27:50 -05003252 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3253 rp++;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003254 }
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003255 break;
3256 }
3257 default:
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003258 png_error(png_ptr, "Ignoring bad adaptive filter type");
3259 /*NOT REACHED */
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05003260 break;
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003261 }
3262}
Guy Schalnat0d580581995-07-20 02:43:20 -05003263
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003264#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003265void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003266png_read_finish_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003267{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003268#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003269 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003270
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003271 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003272 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003273
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003274 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003275 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003276
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003277 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003278 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003279
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003280 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003281 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3282#endif /* PNG_READ_INTERLACING_SUPPORTED */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003283
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003284 png_debug(1, "in png_read_finish_row");
Guy Schalnat0d580581995-07-20 02:43:20 -05003285 png_ptr->row_number++;
3286 if (png_ptr->row_number < png_ptr->num_rows)
3287 return;
3288
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003289#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003290 if (png_ptr->interlaced)
3291 {
3292 png_ptr->row_number = 0;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003293
3294 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
3295
Guy Schalnat0d580581995-07-20 02:43:20 -05003296 do
3297 {
3298 png_ptr->pass++;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003299
Guy Schalnat0d580581995-07-20 02:43:20 -05003300 if (png_ptr->pass >= 7)
3301 break;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003302
Guy Schalnat0d580581995-07-20 02:43:20 -05003303 png_ptr->iwidth = (png_ptr->width +
3304 png_pass_inc[png_ptr->pass] - 1 -
3305 png_pass_start[png_ptr->pass]) /
3306 png_pass_inc[png_ptr->pass];
Glenn Randers-Pehrson272489d2004-08-04 06:34:52 -05003307
Guy Schalnat0d580581995-07-20 02:43:20 -05003308 if (!(png_ptr->transformations & PNG_INTERLACE))
3309 {
3310 png_ptr->num_rows = (png_ptr->height +
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003311 png_pass_yinc[png_ptr->pass] - 1 -
3312 png_pass_ystart[png_ptr->pass]) /
3313 png_pass_yinc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003314 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003315
Glenn Randers-Pehrson345bc271998-06-14 14:43:31 -05003316 else /* if (png_ptr->transformations & PNG_INTERLACE) */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003317 break; /* libpng deinterlacing sees every row */
3318
3319 } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0);
Guy Schalnat0d580581995-07-20 02:43:20 -05003320
3321 if (png_ptr->pass < 7)
3322 return;
3323 }
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003324#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003325
Guy Schalnate5a37791996-06-05 15:50:50 -05003326 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
Guy Schalnat0d580581995-07-20 02:43:20 -05003327 {
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003328 PNG_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003329 char extra;
3330 int ret;
3331
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003332 png_ptr->zstream.next_out = (Byte *)&extra;
3333 png_ptr->zstream.avail_out = (uInt)1;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003334
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003335 for (;;)
Guy Schalnat0d580581995-07-20 02:43:20 -05003336 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003337 if (!(png_ptr->zstream.avail_in))
Guy Schalnat0d580581995-07-20 02:43:20 -05003338 {
3339 while (!png_ptr->idat_size)
3340 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003341 png_crc_finish(png_ptr, 0);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003342 png_ptr->idat_size = png_read_chunk_header(png_ptr);
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003343 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
Guy Schalnat6d764711995-12-19 03:22:19 -06003344 png_error(png_ptr, "Not enough image data");
Glenn Randers-Pehrson20788d32011-01-06 09:01:04 -06003345 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003346
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003347 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3348 png_ptr->zstream.next_in = png_ptr->zbuf;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003349
Guy Schalnat0d580581995-07-20 02:43:20 -05003350 if (png_ptr->zbuf_size > png_ptr->idat_size)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003351 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003352
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003353 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3354 png_ptr->idat_size -= png_ptr->zstream.avail_in;
Guy Schalnat0d580581995-07-20 02:43:20 -05003355 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003356
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003357 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003358
Guy Schalnat0d580581995-07-20 02:43:20 -05003359 if (ret == Z_STREAM_END)
3360 {
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003361 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003362 png_ptr->idat_size)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003363 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003364
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003365 png_ptr->mode |= PNG_AFTER_IDAT;
3366 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
Guy Schalnat0d580581995-07-20 02:43:20 -05003367 break;
3368 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003369
Guy Schalnat0d580581995-07-20 02:43:20 -05003370 if (ret != Z_OK)
Glenn Randers-Pehrsona565f0e2010-03-06 08:24:45 -06003371 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003372 "Decompression Error");
Guy Schalnat0d580581995-07-20 02:43:20 -05003373
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003374 if (!(png_ptr->zstream.avail_out))
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003375 {
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003376 png_warning(png_ptr, "Extra compressed data");
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003377 png_ptr->mode |= PNG_AFTER_IDAT;
3378 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3379 break;
3380 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003381
Glenn Randers-Pehrsonea3bcd71998-03-07 14:33:00 -06003382 }
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003383 png_ptr->zstream.avail_out = 0;
Guy Schalnat0d580581995-07-20 02:43:20 -05003384 }
3385
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003386 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Glenn Randers-Pehrson859665d2002-08-06 18:06:11 -05003387 png_warning(png_ptr, "Extra compression data");
Guy Schalnat0d580581995-07-20 02:43:20 -05003388
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003389 inflateReset(&png_ptr->zstream);
Guy Schalnat0d580581995-07-20 02:43:20 -05003390
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003391 png_ptr->mode |= PNG_AFTER_IDAT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003392}
Glenn Randers-Pehrsondbd40142009-08-31 08:42:02 -05003393#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003394
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -05003395void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -06003396png_read_start_row(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -05003397{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003398#ifdef PNG_READ_INTERLACING_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003399 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003400
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003401 /* Start of interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003402 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003403
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003404 /* Offset to next interlace block */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003405 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003406
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003407 /* Start of interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003408 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003409
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003410 /* Offset to next interlace block in the y direction */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003411 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3412#endif
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -06003413
Guy Schalnat0d580581995-07-20 02:43:20 -05003414 int max_pixel_depth;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003415 png_size_t row_bytes;
Guy Schalnat0d580581995-07-20 02:43:20 -05003416
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -05003417 png_debug(1, "in png_read_start_row");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -06003418 png_ptr->zstream.avail_in = 0;
John Bowler4a12f4a2011-04-17 18:34:22 -05003419#ifdef PNG_READ_TRANSFORMS_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003420 png_init_read_transformations(png_ptr);
John Bowler4a12f4a2011-04-17 18:34:22 -05003421#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003422#ifdef PNG_READ_INTERLACING_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003423 if (png_ptr->interlaced)
3424 {
3425 if (!(png_ptr->transformations & PNG_INTERLACE))
3426 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003427 png_pass_ystart[0]) / png_pass_yinc[0];
3428
Guy Schalnat0d580581995-07-20 02:43:20 -05003429 else
3430 png_ptr->num_rows = png_ptr->height;
3431
3432 png_ptr->iwidth = (png_ptr->width +
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003433 png_pass_inc[png_ptr->pass] - 1 -
3434 png_pass_start[png_ptr->pass]) /
3435 png_pass_inc[png_ptr->pass];
Guy Schalnat0d580581995-07-20 02:43:20 -05003436 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003437
Guy Schalnat0d580581995-07-20 02:43:20 -05003438 else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003439#endif /* PNG_READ_INTERLACING_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -05003440 {
3441 png_ptr->num_rows = png_ptr->height;
3442 png_ptr->iwidth = png_ptr->width;
Guy Schalnat0d580581995-07-20 02:43:20 -05003443 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003444
Guy Schalnat0d580581995-07-20 02:43:20 -05003445 max_pixel_depth = png_ptr->pixel_depth;
3446
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003447#ifdef PNG_READ_PACK_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003448 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
Guy Schalnat0d580581995-07-20 02:43:20 -05003449 max_pixel_depth = 8;
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003450#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003451
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003452#ifdef PNG_READ_EXPAND_SUPPORTED
Guy Schalnate5a37791996-06-05 15:50:50 -05003453 if (png_ptr->transformations & PNG_EXPAND)
Guy Schalnat0d580581995-07-20 02:43:20 -05003454 {
3455 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3456 {
3457 if (png_ptr->num_trans)
3458 max_pixel_depth = 32;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003459
Guy Schalnat0d580581995-07-20 02:43:20 -05003460 else
3461 max_pixel_depth = 24;
3462 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003463
Guy Schalnat0d580581995-07-20 02:43:20 -05003464 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3465 {
3466 if (max_pixel_depth < 8)
3467 max_pixel_depth = 8;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003468
Guy Schalnat0d580581995-07-20 02:43:20 -05003469 if (png_ptr->num_trans)
3470 max_pixel_depth *= 2;
3471 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003472
Guy Schalnat0d580581995-07-20 02:43:20 -05003473 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3474 {
3475 if (png_ptr->num_trans)
3476 {
3477 max_pixel_depth *= 4;
3478 max_pixel_depth /= 3;
3479 }
3480 }
3481 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003482#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003483
John Bowler4d562962011-02-12 09:01:20 -06003484#ifdef PNG_READ_EXPAND_16_SUPPORTED
3485 if (png_ptr->transformations & PNG_EXPAND_16)
3486 {
3487# ifdef PNG_READ_EXPAND_SUPPORTED
3488 /* In fact it is an error if it isn't supported, but checking is
3489 * the safe way.
3490 */
3491 if (png_ptr->transformations & PNG_EXPAND)
3492 {
3493 if (png_ptr->bit_depth < 16)
3494 max_pixel_depth *= 2;
3495 }
3496 else
3497# endif
3498 png_ptr->transformations &= ~PNG_EXPAND_16;
3499 }
3500#endif
3501
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003502#ifdef PNG_READ_FILLER_SUPPORTED
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003503 if (png_ptr->transformations & (PNG_FILLER))
Guy Schalnat0d580581995-07-20 02:43:20 -05003504 {
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003505 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3506 max_pixel_depth = 32;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003507
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003508 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003509 {
3510 if (max_pixel_depth <= 8)
3511 max_pixel_depth = 16;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003512
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003513 else
3514 max_pixel_depth = 32;
3515 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003516
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003517 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3518 {
3519 if (max_pixel_depth <= 32)
3520 max_pixel_depth = 32;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003521
Glenn Randers-Pehrson896239b1998-04-21 15:03:57 -05003522 else
3523 max_pixel_depth = 64;
3524 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003525 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003526#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003527
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003528#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Guy Schalnat0d580581995-07-20 02:43:20 -05003529 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3530 {
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003531 if (
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003532#ifdef PNG_READ_EXPAND_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003533 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003534#endif
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -05003535#ifdef PNG_READ_FILLER_SUPPORTED
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003536 (png_ptr->transformations & (PNG_FILLER)) ||
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003537#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003538 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
Guy Schalnat0d580581995-07-20 02:43:20 -05003539 {
3540 if (max_pixel_depth <= 16)
3541 max_pixel_depth = 32;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003542
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003543 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003544 max_pixel_depth = 64;
3545 }
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003546
Guy Schalnat0d580581995-07-20 02:43:20 -05003547 else
3548 {
3549 if (max_pixel_depth <= 8)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003550 {
3551 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003552 max_pixel_depth = 32;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003553
3554 else
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003555 max_pixel_depth = 24;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003556 }
3557
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -06003558 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3559 max_pixel_depth = 64;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003560
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -06003561 else
Guy Schalnat0d580581995-07-20 02:43:20 -05003562 max_pixel_depth = 48;
3563 }
3564 }
Guy Schalnat51f0eb41995-09-26 05:22:39 -05003565#endif
Guy Schalnat0d580581995-07-20 02:43:20 -05003566
Glenn Randers-Pehrson6942d532000-05-01 09:31:54 -05003567#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3568defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003569 if (png_ptr->transformations & PNG_USER_TRANSFORM)
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003570 {
3571 int user_pixel_depth = png_ptr->user_transform_depth*
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003572 png_ptr->user_transform_channels;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003573
3574 if (user_pixel_depth > max_pixel_depth)
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003575 max_pixel_depth=user_pixel_depth;
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003576 }
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -05003577#endif
3578
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003579 /* Align the width on the next larger 8 pixels. Mainly used
3580 * for interlacing
3581 */
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003582 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -05003583 /* Calculate the maximum bytes needed, adding a byte and a pixel
3584 * for safety's sake
3585 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003586 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003587 1 + ((max_pixel_depth + 7) >> 3);
3588
Guy Schalnat0d580581995-07-20 02:43:20 -05003589#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrsond0dce401998-05-09 10:02:29 -05003590 if (row_bytes > (png_uint_32)65536L)
Guy Schalnate5a37791996-06-05 15:50:50 -05003591 png_error(png_ptr, "This image requires a row greater than 64KB");
Guy Schalnat0d580581995-07-20 02:43:20 -05003592#endif
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003593
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003594 if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003595 {
3596 png_free(png_ptr, png_ptr->big_row_buf);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003597
Glenn Randers-Pehrson6917b512009-03-09 15:31:08 -05003598 if (png_ptr->interlaced)
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003599 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3600 row_bytes + 48);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003601
Glenn Randers-Pehrsona515d302010-01-01 10:24:25 -06003602 else
3603 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3604 row_bytes + 48);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003605
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003606 png_ptr->old_big_row_buf_size = row_bytes + 48;
3607
3608#ifdef PNG_ALIGNED_MEMORY_SUPPORTED
3609 /* Use 16-byte aligned memory for row_buf with at least 16 bytes
3610 * of padding before and after row_buf.
3611 */
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003612 png_ptr->row_buf = png_ptr->big_row_buf + 32 -
3613 (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F);
3614
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003615 png_ptr->old_big_row_buf_size = row_bytes + 48;
3616#else
3617 /* Use 32 bytes of padding before and 16 bytes after row_buf. */
Glenn Randers-Pehrson8fb550c2009-03-21 08:15:32 -05003618 png_ptr->row_buf = png_ptr->big_row_buf + 32;
Glenn Randers-Pehrsoneddc5af2009-11-20 21:15:06 -06003619#endif
3620 png_ptr->old_big_row_buf_size = row_bytes + 48;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003621 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003622
3623#ifdef PNG_MAX_MALLOC_64K
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003624 if (png_ptr->rowbytes > 65535)
Guy Schalnate5a37791996-06-05 15:50:50 -05003625 png_error(png_ptr, "This image requires a row greater than 64KB");
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003626
Guy Schalnat0d580581995-07-20 02:43:20 -05003627#endif
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003628 if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003629 png_error(png_ptr, "Row has too many bytes to allocate in memory");
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003630
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003631 if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003632 {
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003633 png_free(png_ptr, png_ptr->prev_row);
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003634
3635 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
3636
Glenn Randers-Pehrsona98aa482009-10-13 09:23:39 -05003637 png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -05003638 }
Guy Schalnat0d580581995-07-20 02:43:20 -05003639
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -05003640 png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
Andreas Dilger47a0c421997-05-16 02:46:07 -05003641
Glenn Randers-Pehrson5c92dec2011-01-07 18:28:47 -06003642 png_debug1(3, "width = %u,", png_ptr->width);
3643 png_debug1(3, "height = %u,", png_ptr->height);
3644 png_debug1(3, "iwidth = %u,", png_ptr->iwidth);
3645 png_debug1(3, "num_rows = %u,", png_ptr->num_rows);
Glenn Randers-Pehrsonb764c602011-01-14 21:18:37 -06003646 png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes);
3647 png_debug1(3, "irowbytes = %lu",
3648 (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
Guy Schalnat0d580581995-07-20 02:43:20 -05003649
Guy Schalnate5a37791996-06-05 15:50:50 -05003650 png_ptr->flags |= PNG_FLAG_ROW_INIT;
Guy Schalnat0d580581995-07-20 02:43:20 -05003651}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -06003652#endif /* PNG_READ_SUPPORTED */