blob: 1e2db31b25b7cf30f460e52b6fa1302e4cdcea90 [file] [log] [blame]
The Android Open Source Project893912b2009-03-03 19:30:05 -08001
2/* pngrutil.c - utilities to read a PNG file
3 *
Patrick Scott5f6bd842010-06-28 16:55:16 -04004 * Last changed in libpng 1.2.44 [June 26, 2010]
5 * Copyright (c) 1998-2010 Glenn Randers-Pehrson
The Android Open Source Project893912b2009-03-03 19:30:05 -08006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8 *
Patrick Scotta0bb96c2009-07-22 11:50:02 -04009 * This code is released under the libpng license.
10 * For conditions of distribution and use, see the disclaimer
11 * and license in png.h
12 *
The Android Open Source Project893912b2009-03-03 19:30:05 -080013 * This file contains routines that are only called from within
14 * libpng itself during the course of reading an image.
15 */
16
17#define PNG_INTERNAL
Patrick Scott5f6bd842010-06-28 16:55:16 -040018#define PNG_NO_PEDANTIC_WARNINGS
The Android Open Source Project893912b2009-03-03 19:30:05 -080019#include "png.h"
Patrick Scott5f6bd842010-06-28 16:55:16 -040020#ifdef PNG_READ_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -080021
22#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500)
23# define WIN32_WCE_OLD
24#endif
25
26#ifdef PNG_FLOATING_POINT_SUPPORTED
Patrick Scott5f6bd842010-06-28 16:55:16 -040027# ifdef WIN32_WCE_OLD
Patrick Scotta0bb96c2009-07-22 11:50:02 -040028/* The strtod() function is not supported on WindowsCE */
Patrick Scott5f6bd842010-06-28 16:55:16 -040029__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr,
30 char **endptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -080031{
32 double result = 0;
33 int len;
34 wchar_t *str, *end;
35
36 len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
The Android Open Source Project4215dd12009-03-09 11:52:12 -070037 str = (wchar_t *)png_malloc(png_ptr, len * png_sizeof(wchar_t));
The Android Open Source Project893912b2009-03-03 19:30:05 -080038 if ( NULL != str )
39 {
40 MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
41 result = wcstod(str, &end);
42 len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
43 *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
44 png_free(png_ptr, str);
45 }
46 return result;
47}
48# else
49# define png_strtod(p,a,b) strtod(a,b)
50# endif
51#endif
52
53png_uint_32 PNGAPI
54png_get_uint_31(png_structp png_ptr, png_bytep buf)
55{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070056#ifdef PNG_READ_BIG_ENDIAN_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -080057 png_uint_32 i = png_get_uint_32(buf);
The Android Open Source Project4215dd12009-03-09 11:52:12 -070058#else
59 /* Avoid an extra function call by inlining the result. */
60 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
61 ((png_uint_32)(*(buf + 1)) << 16) +
62 ((png_uint_32)(*(buf + 2)) << 8) +
63 (png_uint_32)(*(buf + 3));
64#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -080065 if (i > PNG_UINT_31_MAX)
66 png_error(png_ptr, "PNG unsigned integer out of range.");
67 return (i);
68}
69#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
70/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
71png_uint_32 PNGAPI
72png_get_uint_32(png_bytep buf)
73{
74 png_uint_32 i = ((png_uint_32)(*buf) << 24) +
75 ((png_uint_32)(*(buf + 1)) << 16) +
76 ((png_uint_32)(*(buf + 2)) << 8) +
77 (png_uint_32)(*(buf + 3));
78
79 return (i);
80}
81
82/* Grab a signed 32-bit integer from a buffer in big-endian format. The
83 * data is stored in the PNG file in two's complement format, and it is
Patrick Scotta0bb96c2009-07-22 11:50:02 -040084 * assumed that the machine format for signed integers is the same.
85 */
The Android Open Source Project893912b2009-03-03 19:30:05 -080086png_int_32 PNGAPI
87png_get_int_32(png_bytep buf)
88{
89 png_int_32 i = ((png_int_32)(*buf) << 24) +
90 ((png_int_32)(*(buf + 1)) << 16) +
91 ((png_int_32)(*(buf + 2)) << 8) +
92 (png_int_32)(*(buf + 3));
93
94 return (i);
95}
96
97/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
98png_uint_16 PNGAPI
99png_get_uint_16(png_bytep buf)
100{
101 png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
102 (png_uint_16)(*(buf + 1)));
103
104 return (i);
105}
106#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
107
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700108/* Read the chunk header (length + type name).
109 * Put the type name into png_ptr->chunk_name, and return the length.
110 */
111png_uint_32 /* PRIVATE */
112png_read_chunk_header(png_structp png_ptr)
113{
114 png_byte buf[8];
115 png_uint_32 length;
116
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400117 /* Read the length and the chunk name */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700118 png_read_data(png_ptr, buf, 8);
119 length = png_get_uint_31(png_ptr, buf);
120
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400121 /* Put the chunk name into png_ptr->chunk_name */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700122 png_memcpy(png_ptr->chunk_name, buf + 4, 4);
123
124 png_debug2(0, "Reading %s chunk, length = %lu",
125 png_ptr->chunk_name, length);
126
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400127 /* Reset the crc and run it over the chunk name */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700128 png_reset_crc(png_ptr);
129 png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
130
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400131 /* Check to see if chunk name is valid */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700132 png_check_chunk_name(png_ptr, png_ptr->chunk_name);
133
134 return length;
135}
136
The Android Open Source Project893912b2009-03-03 19:30:05 -0800137/* Read data, and (optionally) run it through the CRC. */
138void /* PRIVATE */
139png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
140{
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400141 if (png_ptr == NULL)
142 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800143 png_read_data(png_ptr, buf, length);
144 png_calculate_crc(png_ptr, buf, length);
145}
146
147/* Optionally skip data and then check the CRC. Depending on whether we
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400148 * are reading a ancillary or critical chunk, and how the program has set
149 * things up, we may calculate the CRC on the data and print a message.
150 * Returns '1' if there was a CRC error, '0' otherwise.
151 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800152int /* PRIVATE */
153png_crc_finish(png_structp png_ptr, png_uint_32 skip)
154{
155 png_size_t i;
156 png_size_t istop = png_ptr->zbuf_size;
157
158 for (i = (png_size_t)skip; i > istop; i -= istop)
159 {
160 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
161 }
162 if (i)
163 {
164 png_crc_read(png_ptr, png_ptr->zbuf, i);
165 }
166
167 if (png_crc_error(png_ptr))
168 {
169 if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400170 !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
The Android Open Source Project893912b2009-03-03 19:30:05 -0800171 (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
172 (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
173 {
174 png_chunk_warning(png_ptr, "CRC error");
175 }
176 else
177 {
178 png_chunk_error(png_ptr, "CRC error");
179 }
180 return (1);
181 }
182
183 return (0);
184}
185
186/* Compare the CRC stored in the PNG file with that calculated by libpng from
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400187 * the data it has read thus far.
188 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800189int /* PRIVATE */
190png_crc_error(png_structp png_ptr)
191{
192 png_byte crc_bytes[4];
193 png_uint_32 crc;
194 int need_crc = 1;
195
196 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
197 {
198 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
199 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
200 need_crc = 0;
201 }
202 else /* critical */
203 {
204 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
205 need_crc = 0;
206 }
207
208 png_read_data(png_ptr, crc_bytes, 4);
209
210 if (need_crc)
211 {
212 crc = png_get_uint_32(crc_bytes);
213 return ((int)(crc != png_ptr->crc));
214 }
215 else
216 return (0);
217}
218
219#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
220 defined(PNG_READ_iCCP_SUPPORTED)
Patrick Scott5f6bd842010-06-28 16:55:16 -0400221static png_size_t
222png_inflate(png_structp png_ptr, const png_byte *data, png_size_t size,
223 png_bytep output, png_size_t output_size)
224{
225 png_size_t count = 0;
226
227 png_ptr->zstream.next_in = (png_bytep)data; /* const_cast: VALID */
228 png_ptr->zstream.avail_in = size;
229
230 while (1)
231 {
232 int ret, avail;
233
234 /* Reset the output buffer each time round - we empty it
235 * after every inflate call.
236 */
237 png_ptr->zstream.next_out = png_ptr->zbuf;
238 png_ptr->zstream.avail_out = png_ptr->zbuf_size;
239
240 ret = inflate(&png_ptr->zstream, Z_NO_FLUSH);
241 avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out;
242
243 /* First copy/count any new output - but only if we didn't
244 * get an error code.
245 */
246 if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0)
247 {
248 if (output != 0 && output_size > count)
249 {
250 int copy = output_size - count;
251 if (avail < copy) copy = avail;
252 png_memcpy(output + count, png_ptr->zbuf, copy);
253 }
254 count += avail;
255 }
256
257 if (ret == Z_OK)
258 continue;
259
260 /* Termination conditions - always reset the zstream, it
261 * must be left in inflateInit state.
262 */
263 png_ptr->zstream.avail_in = 0;
264 inflateReset(&png_ptr->zstream);
265
266 if (ret == Z_STREAM_END)
267 return count; /* NOTE: may be zero. */
268
269 /* Now handle the error codes - the API always returns 0
270 * and the error message is dumped into the uncompressed
271 * buffer if available.
272 */
273 {
274 PNG_CONST char *msg;
275 if (png_ptr->zstream.msg != 0)
276 msg = png_ptr->zstream.msg;
277 else
278 {
279#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
280 char umsg[52];
281
282 switch (ret)
283 {
284 case Z_BUF_ERROR:
285 msg = "Buffer error in compressed datastream in %s chunk";
286 break;
287 case Z_DATA_ERROR:
288 msg = "Data error in compressed datastream in %s chunk";
289 break;
290 default:
291 msg = "Incomplete compressed datastream in %s chunk";
292 break;
293 }
294
295 png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
296 msg = umsg;
297#else
298 msg = "Damaged compressed datastream in chunk other than IDAT";
299#endif
300 }
301
302 png_warning(png_ptr, msg);
303 }
304
305 /* 0 means an error - notice that this code simple ignores
306 * zero length compressed chunks as a result.
307 */
308 return 0;
309 }
310}
311
The Android Open Source Project893912b2009-03-03 19:30:05 -0800312/*
313 * Decompress trailing data in a chunk. The assumption is that chunkdata
314 * points at an allocated area holding the contents of a chunk with a
315 * trailing compressed part. What we get back is an allocated area
316 * holding the original prefix part and an uncompressed version of the
317 * trailing part (the malloc area passed in is freed).
318 */
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700319void /* PRIVATE */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800320png_decompress_chunk(png_structp png_ptr, int comp_type,
Patrick Scott5f6bd842010-06-28 16:55:16 -0400321 png_size_t chunklength,
322 png_size_t prefix_size, png_size_t *newlength)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800323{
Patrick Scott5f6bd842010-06-28 16:55:16 -0400324 /* The caller should guarantee this */
325 if (prefix_size > chunklength)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800326 {
Patrick Scott5f6bd842010-06-28 16:55:16 -0400327 /* The recovery is to delete the chunk. */
328 png_warning(png_ptr, "invalid chunklength");
329 prefix_size = 0; /* To delete everything */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800330 }
Patrick Scott5f6bd842010-06-28 16:55:16 -0400331
332 else if (comp_type == PNG_COMPRESSION_TYPE_BASE)
333 {
334 png_size_t expanded_size = png_inflate(png_ptr,
335 (png_bytep)(png_ptr->chunkdata + prefix_size),
336 chunklength - prefix_size,
337 0/*output*/, 0/*output size*/);
338
339 /* Now check the limits on this chunk - if the limit fails the
340 * compressed data will be removed, the prefix will remain.
341 */
342#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
343 if (png_ptr->user_chunk_malloc_max &&
344 (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
345#else
346# ifdef PNG_USER_CHUNK_MALLOC_MAX
347 if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
348 prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
349# endif
350#endif
351 png_warning(png_ptr, "Exceeded size limit while expanding chunk");
352
353 /* If the size is zero either there was an error and a message
354 * has already been output (warning) or the size really is zero
355 * and we have nothing to do - the code will exit through the
356 * error case below.
357 */
358#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
359 defined(PNG_USER_CHUNK_MALLOC_MAX)
360 else
361#endif
362 if (expanded_size > 0)
363 {
364 /* Success (maybe) - really uncompress the chunk. */
365 png_size_t new_size = 0;
366 png_charp text = png_malloc_warn(png_ptr,
367 prefix_size + expanded_size + 1);
368
369 if (text != NULL)
370 {
371 png_memcpy(text, png_ptr->chunkdata, prefix_size);
372 new_size = png_inflate(png_ptr,
373 (png_bytep)(png_ptr->chunkdata + prefix_size),
374 chunklength - prefix_size,
375 (png_bytep)(text + prefix_size), expanded_size);
376 text[prefix_size + expanded_size] = 0; /* just in case */
377
378 if (new_size == expanded_size)
379 {
380 png_free(png_ptr, png_ptr->chunkdata);
381 png_ptr->chunkdata = text;
382 *newlength = prefix_size + expanded_size;
383 return; /* The success return! */
384 }
385
386 png_warning(png_ptr, "png_inflate logic error");
387 png_free(png_ptr, text);
388 }
389 else
390 png_warning(png_ptr, "Not enough memory to decompress chunk.");
391 }
392 }
393
The Android Open Source Project893912b2009-03-03 19:30:05 -0800394 else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
395 {
Patrick Scott5f6bd842010-06-28 16:55:16 -0400396#if defined(PNG_STDIO_SUPPORTED) && !defined(_WIN32_WCE)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800397 char umsg[50];
398
Patrick Scott5f6bd842010-06-28 16:55:16 -0400399 png_snprintf(umsg, sizeof umsg, "Unknown zTXt compression type %d",
400 comp_type);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800401 png_warning(png_ptr, umsg);
402#else
403 png_warning(png_ptr, "Unknown zTXt compression type");
404#endif
405
Patrick Scott5f6bd842010-06-28 16:55:16 -0400406 /* The recovery is to simply drop the data. */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800407 }
Patrick Scott5f6bd842010-06-28 16:55:16 -0400408
409 /* Generic error return - leave the prefix, delete the compressed
410 * data, reallocate the chunkdata to remove the potentially large
411 * amount of compressed data.
412 */
413 {
414 png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
415 if (text != NULL)
416 {
417 if (prefix_size > 0)
418 png_memcpy(text, png_ptr->chunkdata, prefix_size);
419 png_free(png_ptr, png_ptr->chunkdata);
420 png_ptr->chunkdata = text;
421
422 /* This is an extra zero in the 'uncompressed' part. */
423 *(png_ptr->chunkdata + prefix_size) = 0x00;
424 }
425 /* Ignore a malloc error here - it is safe. */
426 }
427
428 *newlength = prefix_size;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800429}
430#endif
431
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400432/* Read and check the IDHR chunk */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800433void /* PRIVATE */
434png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
435{
436 png_byte buf[13];
437 png_uint_32 width, height;
438 int bit_depth, color_type, compression_type, filter_type;
439 int interlace_type;
440
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700441 png_debug(1, "in png_handle_IHDR");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800442
443 if (png_ptr->mode & PNG_HAVE_IHDR)
444 png_error(png_ptr, "Out of place IHDR");
445
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400446 /* Check the length */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800447 if (length != 13)
448 png_error(png_ptr, "Invalid IHDR chunk");
449
450 png_ptr->mode |= PNG_HAVE_IHDR;
451
452 png_crc_read(png_ptr, buf, 13);
453 png_crc_finish(png_ptr, 0);
454
455 width = png_get_uint_31(png_ptr, buf);
456 height = png_get_uint_31(png_ptr, buf + 4);
457 bit_depth = buf[8];
458 color_type = buf[9];
459 compression_type = buf[10];
460 filter_type = buf[11];
461 interlace_type = buf[12];
462
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400463 /* Set internal variables */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800464 png_ptr->width = width;
465 png_ptr->height = height;
466 png_ptr->bit_depth = (png_byte)bit_depth;
467 png_ptr->interlaced = (png_byte)interlace_type;
468 png_ptr->color_type = (png_byte)color_type;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400469#ifdef PNG_MNG_FEATURES_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800470 png_ptr->filter_type = (png_byte)filter_type;
471#endif
472 png_ptr->compression_type = (png_byte)compression_type;
473
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400474 /* Find number of channels */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800475 switch (png_ptr->color_type)
476 {
477 case PNG_COLOR_TYPE_GRAY:
478 case PNG_COLOR_TYPE_PALETTE:
479 png_ptr->channels = 1;
480 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400481
The Android Open Source Project893912b2009-03-03 19:30:05 -0800482 case PNG_COLOR_TYPE_RGB:
483 png_ptr->channels = 3;
484 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400485
The Android Open Source Project893912b2009-03-03 19:30:05 -0800486 case PNG_COLOR_TYPE_GRAY_ALPHA:
487 png_ptr->channels = 2;
488 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400489
The Android Open Source Project893912b2009-03-03 19:30:05 -0800490 case PNG_COLOR_TYPE_RGB_ALPHA:
491 png_ptr->channels = 4;
492 break;
493 }
494
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400495 /* Set up other useful info */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800496 png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
497 png_ptr->channels);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700498 png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width);
499 png_debug1(3, "bit_depth = %d", png_ptr->bit_depth);
500 png_debug1(3, "channels = %d", png_ptr->channels);
501 png_debug1(3, "rowbytes = %lu", png_ptr->rowbytes);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800502 png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
503 color_type, interlace_type, compression_type, filter_type);
504}
505
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400506/* Read and check the palette */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800507void /* PRIVATE */
508png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
509{
510 png_color palette[PNG_MAX_PALETTE_LENGTH];
511 int num, i;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400512#ifdef PNG_POINTER_INDEXING_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800513 png_colorp pal_ptr;
514#endif
515
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700516 png_debug(1, "in png_handle_PLTE");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800517
518 if (!(png_ptr->mode & PNG_HAVE_IHDR))
519 png_error(png_ptr, "Missing IHDR before PLTE");
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400520
The Android Open Source Project893912b2009-03-03 19:30:05 -0800521 else if (png_ptr->mode & PNG_HAVE_IDAT)
522 {
523 png_warning(png_ptr, "Invalid PLTE after IDAT");
524 png_crc_finish(png_ptr, length);
525 return;
526 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400527
The Android Open Source Project893912b2009-03-03 19:30:05 -0800528 else if (png_ptr->mode & PNG_HAVE_PLTE)
529 png_error(png_ptr, "Duplicate PLTE chunk");
530
531 png_ptr->mode |= PNG_HAVE_PLTE;
532
533 if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
534 {
535 png_warning(png_ptr,
536 "Ignoring PLTE chunk in grayscale PNG");
537 png_crc_finish(png_ptr, length);
538 return;
539 }
Patrick Scott5f6bd842010-06-28 16:55:16 -0400540#ifndef PNG_READ_OPT_PLTE_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800541 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
542 {
543 png_crc_finish(png_ptr, length);
544 return;
545 }
546#endif
547
548 if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
549 {
550 if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
551 {
552 png_warning(png_ptr, "Invalid palette chunk");
553 png_crc_finish(png_ptr, length);
554 return;
555 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400556
The Android Open Source Project893912b2009-03-03 19:30:05 -0800557 else
558 {
559 png_error(png_ptr, "Invalid palette chunk");
560 }
561 }
562
563 num = (int)length / 3;
564
Patrick Scott5f6bd842010-06-28 16:55:16 -0400565#ifdef PNG_POINTER_INDEXING_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800566 for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
567 {
568 png_byte buf[3];
569
570 png_crc_read(png_ptr, buf, 3);
571 pal_ptr->red = buf[0];
572 pal_ptr->green = buf[1];
573 pal_ptr->blue = buf[2];
574 }
575#else
576 for (i = 0; i < num; i++)
577 {
578 png_byte buf[3];
579
580 png_crc_read(png_ptr, buf, 3);
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400581 /* Don't depend upon png_color being any order */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800582 palette[i].red = buf[0];
583 palette[i].green = buf[1];
584 palette[i].blue = buf[2];
585 }
586#endif
587
588 /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400589 * whatever the normal CRC configuration tells us. However, if we
590 * have an RGB image, the PLTE can be considered ancillary, so
591 * we will act as though it is.
592 */
Patrick Scott5f6bd842010-06-28 16:55:16 -0400593#ifndef PNG_READ_OPT_PLTE_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800594 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
595#endif
596 {
597 png_crc_finish(png_ptr, 0);
598 }
Patrick Scott5f6bd842010-06-28 16:55:16 -0400599#ifndef PNG_READ_OPT_PLTE_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800600 else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
601 {
602 /* If we don't want to use the data from an ancillary chunk,
603 we have two options: an error abort, or a warning and we
604 ignore the data in this chunk (which should be OK, since
605 it's considered ancillary for a RGB or RGBA image). */
606 if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
607 {
608 if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
609 {
610 png_chunk_error(png_ptr, "CRC error");
611 }
612 else
613 {
614 png_chunk_warning(png_ptr, "CRC error");
615 return;
616 }
617 }
618 /* Otherwise, we (optionally) emit a warning and use the chunk. */
619 else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
620 {
621 png_chunk_warning(png_ptr, "CRC error");
622 }
623 }
624#endif
625
626 png_set_PLTE(png_ptr, info_ptr, palette, num);
627
Patrick Scott5f6bd842010-06-28 16:55:16 -0400628#ifdef PNG_READ_tRNS_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800629 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
630 {
631 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
632 {
633 if (png_ptr->num_trans > (png_uint_16)num)
634 {
635 png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
636 png_ptr->num_trans = (png_uint_16)num;
637 }
638 if (info_ptr->num_trans > (png_uint_16)num)
639 {
640 png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
641 info_ptr->num_trans = (png_uint_16)num;
642 }
643 }
644 }
645#endif
646
647}
648
649void /* PRIVATE */
650png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
651{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700652 png_debug(1, "in png_handle_IEND");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800653
654 if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
655 {
656 png_error(png_ptr, "No image in file");
657 }
658
659 png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
660
661 if (length != 0)
662 {
663 png_warning(png_ptr, "Incorrect IEND chunk length");
664 }
665 png_crc_finish(png_ptr, length);
666
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400667 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800668}
669
Patrick Scott5f6bd842010-06-28 16:55:16 -0400670#ifdef PNG_READ_gAMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800671void /* PRIVATE */
672png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
673{
674 png_fixed_point igamma;
675#ifdef PNG_FLOATING_POINT_SUPPORTED
676 float file_gamma;
677#endif
678 png_byte buf[4];
679
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700680 png_debug(1, "in png_handle_gAMA");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800681
682 if (!(png_ptr->mode & PNG_HAVE_IHDR))
683 png_error(png_ptr, "Missing IHDR before gAMA");
684 else if (png_ptr->mode & PNG_HAVE_IDAT)
685 {
686 png_warning(png_ptr, "Invalid gAMA after IDAT");
687 png_crc_finish(png_ptr, length);
688 return;
689 }
690 else if (png_ptr->mode & PNG_HAVE_PLTE)
691 /* Should be an error, but we can cope with it */
692 png_warning(png_ptr, "Out of place gAMA chunk");
693
694 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
Patrick Scott5f6bd842010-06-28 16:55:16 -0400695#ifdef PNG_READ_sRGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800696 && !(info_ptr->valid & PNG_INFO_sRGB)
697#endif
698 )
699 {
700 png_warning(png_ptr, "Duplicate gAMA chunk");
701 png_crc_finish(png_ptr, length);
702 return;
703 }
704
705 if (length != 4)
706 {
707 png_warning(png_ptr, "Incorrect gAMA chunk length");
708 png_crc_finish(png_ptr, length);
709 return;
710 }
711
712 png_crc_read(png_ptr, buf, 4);
713 if (png_crc_finish(png_ptr, 0))
714 return;
715
716 igamma = (png_fixed_point)png_get_uint_32(buf);
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400717 /* Check for zero gamma */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800718 if (igamma == 0)
719 {
720 png_warning(png_ptr,
721 "Ignoring gAMA chunk with gamma=0");
722 return;
723 }
724
Patrick Scott5f6bd842010-06-28 16:55:16 -0400725#ifdef PNG_READ_sRGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800726 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
727 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
728 {
729 png_warning(png_ptr,
730 "Ignoring incorrect gAMA value when sRGB is also present");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400731#ifdef PNG_CONSOLE_IO_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700732 fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800733#endif
734 return;
735 }
736#endif /* PNG_READ_sRGB_SUPPORTED */
737
738#ifdef PNG_FLOATING_POINT_SUPPORTED
739 file_gamma = (float)igamma / (float)100000.0;
740# ifdef PNG_READ_GAMMA_SUPPORTED
741 png_ptr->gamma = file_gamma;
742# endif
743 png_set_gAMA(png_ptr, info_ptr, file_gamma);
744#endif
745#ifdef PNG_FIXED_POINT_SUPPORTED
746 png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
747#endif
748}
749#endif
750
Patrick Scott5f6bd842010-06-28 16:55:16 -0400751#ifdef PNG_READ_sBIT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800752void /* PRIVATE */
753png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
754{
755 png_size_t truelen;
756 png_byte buf[4];
757
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700758 png_debug(1, "in png_handle_sBIT");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800759
760 buf[0] = buf[1] = buf[2] = buf[3] = 0;
761
762 if (!(png_ptr->mode & PNG_HAVE_IHDR))
763 png_error(png_ptr, "Missing IHDR before sBIT");
764 else if (png_ptr->mode & PNG_HAVE_IDAT)
765 {
766 png_warning(png_ptr, "Invalid sBIT after IDAT");
767 png_crc_finish(png_ptr, length);
768 return;
769 }
770 else if (png_ptr->mode & PNG_HAVE_PLTE)
771 {
772 /* Should be an error, but we can cope with it */
773 png_warning(png_ptr, "Out of place sBIT chunk");
774 }
775 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
776 {
777 png_warning(png_ptr, "Duplicate sBIT chunk");
778 png_crc_finish(png_ptr, length);
779 return;
780 }
781
782 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
783 truelen = 3;
784 else
785 truelen = (png_size_t)png_ptr->channels;
786
787 if (length != truelen || length > 4)
788 {
789 png_warning(png_ptr, "Incorrect sBIT chunk length");
790 png_crc_finish(png_ptr, length);
791 return;
792 }
793
794 png_crc_read(png_ptr, buf, truelen);
795 if (png_crc_finish(png_ptr, 0))
796 return;
797
798 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
799 {
800 png_ptr->sig_bit.red = buf[0];
801 png_ptr->sig_bit.green = buf[1];
802 png_ptr->sig_bit.blue = buf[2];
803 png_ptr->sig_bit.alpha = buf[3];
804 }
805 else
806 {
807 png_ptr->sig_bit.gray = buf[0];
808 png_ptr->sig_bit.red = buf[0];
809 png_ptr->sig_bit.green = buf[0];
810 png_ptr->sig_bit.blue = buf[0];
811 png_ptr->sig_bit.alpha = buf[1];
812 }
813 png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
814}
815#endif
816
Patrick Scott5f6bd842010-06-28 16:55:16 -0400817#ifdef PNG_READ_cHRM_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800818void /* PRIVATE */
819png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
820{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700821 png_byte buf[32];
The Android Open Source Project893912b2009-03-03 19:30:05 -0800822#ifdef PNG_FLOATING_POINT_SUPPORTED
823 float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
824#endif
825 png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
826 int_y_green, int_x_blue, int_y_blue;
827
828 png_uint_32 uint_x, uint_y;
829
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700830 png_debug(1, "in png_handle_cHRM");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800831
832 if (!(png_ptr->mode & PNG_HAVE_IHDR))
833 png_error(png_ptr, "Missing IHDR before cHRM");
834 else if (png_ptr->mode & PNG_HAVE_IDAT)
835 {
836 png_warning(png_ptr, "Invalid cHRM after IDAT");
837 png_crc_finish(png_ptr, length);
838 return;
839 }
840 else if (png_ptr->mode & PNG_HAVE_PLTE)
841 /* Should be an error, but we can cope with it */
842 png_warning(png_ptr, "Missing PLTE before cHRM");
843
844 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
Patrick Scott5f6bd842010-06-28 16:55:16 -0400845#ifdef PNG_READ_sRGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800846 && !(info_ptr->valid & PNG_INFO_sRGB)
847#endif
848 )
849 {
850 png_warning(png_ptr, "Duplicate cHRM chunk");
851 png_crc_finish(png_ptr, length);
852 return;
853 }
854
855 if (length != 32)
856 {
857 png_warning(png_ptr, "Incorrect cHRM chunk length");
858 png_crc_finish(png_ptr, length);
859 return;
860 }
861
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700862 png_crc_read(png_ptr, buf, 32);
863 if (png_crc_finish(png_ptr, 0))
The Android Open Source Project893912b2009-03-03 19:30:05 -0800864 return;
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700865
866 uint_x = png_get_uint_32(buf);
867 uint_y = png_get_uint_32(buf + 4);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800868 int_x_white = (png_fixed_point)uint_x;
869 int_y_white = (png_fixed_point)uint_y;
870
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700871 uint_x = png_get_uint_32(buf + 8);
872 uint_y = png_get_uint_32(buf + 12);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800873 int_x_red = (png_fixed_point)uint_x;
874 int_y_red = (png_fixed_point)uint_y;
875
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700876 uint_x = png_get_uint_32(buf + 16);
877 uint_y = png_get_uint_32(buf + 20);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800878 int_x_green = (png_fixed_point)uint_x;
879 int_y_green = (png_fixed_point)uint_y;
880
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700881 uint_x = png_get_uint_32(buf + 24);
882 uint_y = png_get_uint_32(buf + 28);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800883 int_x_blue = (png_fixed_point)uint_x;
884 int_y_blue = (png_fixed_point)uint_y;
885
886#ifdef PNG_FLOATING_POINT_SUPPORTED
887 white_x = (float)int_x_white / (float)100000.0;
888 white_y = (float)int_y_white / (float)100000.0;
889 red_x = (float)int_x_red / (float)100000.0;
890 red_y = (float)int_y_red / (float)100000.0;
891 green_x = (float)int_x_green / (float)100000.0;
892 green_y = (float)int_y_green / (float)100000.0;
893 blue_x = (float)int_x_blue / (float)100000.0;
894 blue_y = (float)int_y_blue / (float)100000.0;
895#endif
896
Patrick Scott5f6bd842010-06-28 16:55:16 -0400897#ifdef PNG_READ_sRGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800898 if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
899 {
900 if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
901 PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
902 PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
903 PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
904 PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
905 PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
906 PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
907 PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
908 {
909 png_warning(png_ptr,
910 "Ignoring incorrect cHRM value when sRGB is also present");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400911#ifdef PNG_CONSOLE_IO_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800912#ifdef PNG_FLOATING_POINT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700913 fprintf(stderr, "wx=%f, wy=%f, rx=%f, ry=%f\n",
The Android Open Source Project893912b2009-03-03 19:30:05 -0800914 white_x, white_y, red_x, red_y);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700915 fprintf(stderr, "gx=%f, gy=%f, bx=%f, by=%f\n",
The Android Open Source Project893912b2009-03-03 19:30:05 -0800916 green_x, green_y, blue_x, blue_y);
917#else
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700918 fprintf(stderr, "wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
Patrick Scott5f6bd842010-06-28 16:55:16 -0400919 (long)int_x_white, (long)int_y_white,
920 (long)int_x_red, (long)int_y_red);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700921 fprintf(stderr, "gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
Patrick Scott5f6bd842010-06-28 16:55:16 -0400922 (long)int_x_green, (long)int_y_green,
923 (long)int_x_blue, (long)int_y_blue);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800924#endif
Patrick Scott5f6bd842010-06-28 16:55:16 -0400925#endif /* PNG_CONSOLE_IO_SUPPORTED */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800926 }
The Android Open Source Project893912b2009-03-03 19:30:05 -0800927 return;
928 }
929#endif /* PNG_READ_sRGB_SUPPORTED */
930
931#ifdef PNG_FLOATING_POINT_SUPPORTED
932 png_set_cHRM(png_ptr, info_ptr,
933 white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
934#endif
935#ifdef PNG_FIXED_POINT_SUPPORTED
936 png_set_cHRM_fixed(png_ptr, info_ptr,
937 int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
938 int_y_green, int_x_blue, int_y_blue);
939#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -0800940}
941#endif
942
Patrick Scott5f6bd842010-06-28 16:55:16 -0400943#ifdef PNG_READ_sRGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800944void /* PRIVATE */
945png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
946{
947 int intent;
948 png_byte buf[1];
949
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700950 png_debug(1, "in png_handle_sRGB");
The Android Open Source Project893912b2009-03-03 19:30:05 -0800951
952 if (!(png_ptr->mode & PNG_HAVE_IHDR))
953 png_error(png_ptr, "Missing IHDR before sRGB");
954 else if (png_ptr->mode & PNG_HAVE_IDAT)
955 {
956 png_warning(png_ptr, "Invalid sRGB after IDAT");
957 png_crc_finish(png_ptr, length);
958 return;
959 }
960 else if (png_ptr->mode & PNG_HAVE_PLTE)
961 /* Should be an error, but we can cope with it */
962 png_warning(png_ptr, "Out of place sRGB chunk");
963
964 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
965 {
966 png_warning(png_ptr, "Duplicate sRGB chunk");
967 png_crc_finish(png_ptr, length);
968 return;
969 }
970
971 if (length != 1)
972 {
973 png_warning(png_ptr, "Incorrect sRGB chunk length");
974 png_crc_finish(png_ptr, length);
975 return;
976 }
977
978 png_crc_read(png_ptr, buf, 1);
979 if (png_crc_finish(png_ptr, 0))
980 return;
981
982 intent = buf[0];
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400983 /* Check for bad intent */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800984 if (intent >= PNG_sRGB_INTENT_LAST)
985 {
986 png_warning(png_ptr, "Unknown sRGB intent");
987 return;
988 }
989
990#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
991 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
992 {
993 png_fixed_point igamma;
994#ifdef PNG_FIXED_POINT_SUPPORTED
995 igamma=info_ptr->int_gamma;
996#else
997# ifdef PNG_FLOATING_POINT_SUPPORTED
998 igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
999# endif
1000#endif
1001 if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
1002 {
1003 png_warning(png_ptr,
1004 "Ignoring incorrect gAMA value when sRGB is also present");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001005#ifdef PNG_CONSOLE_IO_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001006# ifdef PNG_FIXED_POINT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001007 fprintf(stderr, "incorrect gamma=(%d/100000)\n",
1008 (int)png_ptr->int_gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001009# else
1010# ifdef PNG_FLOATING_POINT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001011 fprintf(stderr, "incorrect gamma=%f\n", png_ptr->gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001012# endif
1013# endif
1014#endif
1015 }
1016 }
1017#endif /* PNG_READ_gAMA_SUPPORTED */
1018
1019#ifdef PNG_READ_cHRM_SUPPORTED
1020#ifdef PNG_FIXED_POINT_SUPPORTED
1021 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
1022 if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
1023 PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
1024 PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
1025 PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
1026 PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
1027 PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
1028 PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
1029 PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
1030 {
1031 png_warning(png_ptr,
1032 "Ignoring incorrect cHRM value when sRGB is also present");
1033 }
1034#endif /* PNG_FIXED_POINT_SUPPORTED */
1035#endif /* PNG_READ_cHRM_SUPPORTED */
1036
1037 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
1038}
1039#endif /* PNG_READ_sRGB_SUPPORTED */
1040
Patrick Scott5f6bd842010-06-28 16:55:16 -04001041#ifdef PNG_READ_iCCP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001042void /* PRIVATE */
1043png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1044/* Note: this does not properly handle chunks that are > 64K under DOS */
1045{
The Android Open Source Project893912b2009-03-03 19:30:05 -08001046 png_byte compression_type;
1047 png_bytep pC;
1048 png_charp profile;
1049 png_uint_32 skip = 0;
1050 png_uint_32 profile_size, profile_length;
1051 png_size_t slength, prefix_length, data_length;
1052
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001053 png_debug(1, "in png_handle_iCCP");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001054
1055 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1056 png_error(png_ptr, "Missing IHDR before iCCP");
1057 else if (png_ptr->mode & PNG_HAVE_IDAT)
1058 {
1059 png_warning(png_ptr, "Invalid iCCP after IDAT");
1060 png_crc_finish(png_ptr, length);
1061 return;
1062 }
1063 else if (png_ptr->mode & PNG_HAVE_PLTE)
1064 /* Should be an error, but we can cope with it */
1065 png_warning(png_ptr, "Out of place iCCP chunk");
1066
1067 if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
1068 {
1069 png_warning(png_ptr, "Duplicate iCCP chunk");
1070 png_crc_finish(png_ptr, length);
1071 return;
1072 }
1073
1074#ifdef PNG_MAX_MALLOC_64K
1075 if (length > (png_uint_32)65535L)
1076 {
1077 png_warning(png_ptr, "iCCP chunk too large to fit in memory");
1078 skip = length - (png_uint_32)65535L;
1079 length = (png_uint_32)65535L;
1080 }
1081#endif
1082
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001083 png_free(png_ptr, png_ptr->chunkdata);
1084 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001085 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001086 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001087
1088 if (png_crc_finish(png_ptr, skip))
1089 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001090 png_free(png_ptr, png_ptr->chunkdata);
1091 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001092 return;
1093 }
1094
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001095 png_ptr->chunkdata[slength] = 0x00;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001096
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001097 for (profile = png_ptr->chunkdata; *profile; profile++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001098 /* Empty loop to find end of name */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001099
1100 ++profile;
1101
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001102 /* There should be at least one zero (the compression type byte)
1103 * following the separator, and we should be on it
1104 */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001105 if ( profile >= png_ptr->chunkdata + slength - 1)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001106 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001107 png_free(png_ptr, png_ptr->chunkdata);
1108 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001109 png_warning(png_ptr, "Malformed iCCP chunk");
1110 return;
1111 }
1112
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001113 /* Compression_type should always be zero */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001114 compression_type = *profile++;
1115 if (compression_type)
1116 {
1117 png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001118 compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
The Android Open Source Project893912b2009-03-03 19:30:05 -08001119 wrote nonzero) */
1120 }
1121
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001122 prefix_length = profile - png_ptr->chunkdata;
1123 png_decompress_chunk(png_ptr, compression_type,
1124 slength, prefix_length, &data_length);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001125
1126 profile_length = data_length - prefix_length;
1127
1128 if ( prefix_length > data_length || profile_length < 4)
1129 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001130 png_free(png_ptr, png_ptr->chunkdata);
1131 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001132 png_warning(png_ptr, "Profile size field missing from iCCP chunk");
1133 return;
1134 }
1135
1136 /* Check the profile_size recorded in the first 32 bits of the ICC profile */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001137 pC = (png_bytep)(png_ptr->chunkdata + prefix_length);
1138 profile_size = ((*(pC ))<<24) |
1139 ((*(pC + 1))<<16) |
1140 ((*(pC + 2))<< 8) |
1141 ((*(pC + 3)) );
The Android Open Source Project893912b2009-03-03 19:30:05 -08001142
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001143 if (profile_size < profile_length)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001144 profile_length = profile_size;
1145
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001146 if (profile_size > profile_length)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001147 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001148 png_free(png_ptr, png_ptr->chunkdata);
1149 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001150 png_warning(png_ptr, "Ignoring truncated iCCP profile.");
1151 return;
1152 }
1153
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001154 png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata,
1155 compression_type, png_ptr->chunkdata + prefix_length, profile_length);
1156 png_free(png_ptr, png_ptr->chunkdata);
1157 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001158}
1159#endif /* PNG_READ_iCCP_SUPPORTED */
1160
Patrick Scott5f6bd842010-06-28 16:55:16 -04001161#ifdef PNG_READ_sPLT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001162void /* PRIVATE */
1163png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1164/* Note: this does not properly handle chunks that are > 64K under DOS */
1165{
The Android Open Source Project893912b2009-03-03 19:30:05 -08001166 png_bytep entry_start;
1167 png_sPLT_t new_palette;
Patrick Scott5f6bd842010-06-28 16:55:16 -04001168#ifdef PNG_POINTER_INDEXING_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001169 png_sPLT_entryp pp;
1170#endif
1171 int data_length, entry_size, i;
1172 png_uint_32 skip = 0;
1173 png_size_t slength;
1174
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001175 png_debug(1, "in png_handle_sPLT");
1176
Patrick Scott5f6bd842010-06-28 16:55:16 -04001177#ifdef PNG_USER_LIMITS_SUPPORTED
1178
1179 if (png_ptr->user_chunk_cache_max != 0)
1180 {
1181 if (png_ptr->user_chunk_cache_max == 1)
1182 {
1183 png_crc_finish(png_ptr, length);
1184 return;
1185 }
1186 if (--png_ptr->user_chunk_cache_max == 1)
1187 {
1188 png_warning(png_ptr, "No space in chunk cache for sPLT");
1189 png_crc_finish(png_ptr, length);
1190 return;
1191 }
1192 }
1193#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08001194
1195 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1196 png_error(png_ptr, "Missing IHDR before sPLT");
1197 else if (png_ptr->mode & PNG_HAVE_IDAT)
1198 {
1199 png_warning(png_ptr, "Invalid sPLT after IDAT");
1200 png_crc_finish(png_ptr, length);
1201 return;
1202 }
1203
1204#ifdef PNG_MAX_MALLOC_64K
1205 if (length > (png_uint_32)65535L)
1206 {
1207 png_warning(png_ptr, "sPLT chunk too large to fit in memory");
1208 skip = length - (png_uint_32)65535L;
1209 length = (png_uint_32)65535L;
1210 }
1211#endif
1212
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001213 png_free(png_ptr, png_ptr->chunkdata);
1214 png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001215 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001216 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001217
1218 if (png_crc_finish(png_ptr, skip))
1219 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001220 png_free(png_ptr, png_ptr->chunkdata);
1221 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001222 return;
1223 }
1224
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001225 png_ptr->chunkdata[slength] = 0x00;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001226
Patrick Scott5f6bd842010-06-28 16:55:16 -04001227 for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start;
1228 entry_start++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001229 /* Empty loop to find end of name */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001230 ++entry_start;
1231
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001232 /* A sample depth should follow the separator, and we should be on it */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001233 if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001234 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001235 png_free(png_ptr, png_ptr->chunkdata);
1236 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001237 png_warning(png_ptr, "malformed sPLT chunk");
1238 return;
1239 }
1240
1241 new_palette.depth = *entry_start++;
1242 entry_size = (new_palette.depth == 8 ? 6 : 10);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001243 data_length = (slength - (entry_start - (png_bytep)png_ptr->chunkdata));
The Android Open Source Project893912b2009-03-03 19:30:05 -08001244
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001245 /* Integrity-check the data length */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001246 if (data_length % entry_size)
1247 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001248 png_free(png_ptr, png_ptr->chunkdata);
1249 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001250 png_warning(png_ptr, "sPLT chunk has bad length");
1251 return;
1252 }
1253
1254 new_palette.nentries = (png_int_32) ( data_length / entry_size);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001255 if ((png_uint_32) new_palette.nentries >
1256 (png_uint_32) (PNG_SIZE_MAX / png_sizeof(png_sPLT_entry)))
The Android Open Source Project893912b2009-03-03 19:30:05 -08001257 {
1258 png_warning(png_ptr, "sPLT chunk too long");
1259 return;
1260 }
1261 new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
1262 png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
1263 if (new_palette.entries == NULL)
1264 {
1265 png_warning(png_ptr, "sPLT chunk requires too much memory");
1266 return;
1267 }
1268
Patrick Scott5f6bd842010-06-28 16:55:16 -04001269#ifdef PNG_POINTER_INDEXING_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001270 for (i = 0; i < new_palette.nentries; i++)
1271 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04001272 pp = new_palette.entries + i;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001273
1274 if (new_palette.depth == 8)
1275 {
1276 pp->red = *entry_start++;
1277 pp->green = *entry_start++;
1278 pp->blue = *entry_start++;
1279 pp->alpha = *entry_start++;
1280 }
1281 else
1282 {
1283 pp->red = png_get_uint_16(entry_start); entry_start += 2;
1284 pp->green = png_get_uint_16(entry_start); entry_start += 2;
1285 pp->blue = png_get_uint_16(entry_start); entry_start += 2;
1286 pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
1287 }
1288 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1289 }
1290#else
1291 pp = new_palette.entries;
1292 for (i = 0; i < new_palette.nentries; i++)
1293 {
1294
1295 if (new_palette.depth == 8)
1296 {
1297 pp[i].red = *entry_start++;
1298 pp[i].green = *entry_start++;
1299 pp[i].blue = *entry_start++;
1300 pp[i].alpha = *entry_start++;
1301 }
1302 else
1303 {
1304 pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
1305 pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
1306 pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
1307 pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
1308 }
1309 pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
1310 }
1311#endif
1312
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001313 /* Discard all chunk data except the name and stash that */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001314 new_palette.name = png_ptr->chunkdata;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001315
1316 png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
1317
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001318 png_free(png_ptr, png_ptr->chunkdata);
1319 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001320 png_free(png_ptr, new_palette.entries);
1321}
1322#endif /* PNG_READ_sPLT_SUPPORTED */
1323
Patrick Scott5f6bd842010-06-28 16:55:16 -04001324#ifdef PNG_READ_tRNS_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001325void /* PRIVATE */
1326png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1327{
1328 png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
1329
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001330 png_debug(1, "in png_handle_tRNS");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001331
1332 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1333 png_error(png_ptr, "Missing IHDR before tRNS");
1334 else if (png_ptr->mode & PNG_HAVE_IDAT)
1335 {
1336 png_warning(png_ptr, "Invalid tRNS after IDAT");
1337 png_crc_finish(png_ptr, length);
1338 return;
1339 }
1340 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
1341 {
1342 png_warning(png_ptr, "Duplicate tRNS chunk");
1343 png_crc_finish(png_ptr, length);
1344 return;
1345 }
1346
1347 if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
1348 {
1349 png_byte buf[2];
1350
1351 if (length != 2)
1352 {
1353 png_warning(png_ptr, "Incorrect tRNS chunk length");
1354 png_crc_finish(png_ptr, length);
1355 return;
1356 }
1357
1358 png_crc_read(png_ptr, buf, 2);
1359 png_ptr->num_trans = 1;
1360 png_ptr->trans_values.gray = png_get_uint_16(buf);
1361 }
1362 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
1363 {
1364 png_byte buf[6];
1365
1366 if (length != 6)
1367 {
1368 png_warning(png_ptr, "Incorrect tRNS chunk length");
1369 png_crc_finish(png_ptr, length);
1370 return;
1371 }
1372 png_crc_read(png_ptr, buf, (png_size_t)length);
1373 png_ptr->num_trans = 1;
1374 png_ptr->trans_values.red = png_get_uint_16(buf);
1375 png_ptr->trans_values.green = png_get_uint_16(buf + 2);
1376 png_ptr->trans_values.blue = png_get_uint_16(buf + 4);
1377 }
1378 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1379 {
1380 if (!(png_ptr->mode & PNG_HAVE_PLTE))
1381 {
1382 /* Should be an error, but we can cope with it. */
1383 png_warning(png_ptr, "Missing PLTE before tRNS");
1384 }
1385 if (length > (png_uint_32)png_ptr->num_palette ||
1386 length > PNG_MAX_PALETTE_LENGTH)
1387 {
1388 png_warning(png_ptr, "Incorrect tRNS chunk length");
1389 png_crc_finish(png_ptr, length);
1390 return;
1391 }
1392 if (length == 0)
1393 {
1394 png_warning(png_ptr, "Zero length tRNS chunk");
1395 png_crc_finish(png_ptr, length);
1396 return;
1397 }
1398 png_crc_read(png_ptr, readbuf, (png_size_t)length);
1399 png_ptr->num_trans = (png_uint_16)length;
1400 }
1401 else
1402 {
1403 png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
1404 png_crc_finish(png_ptr, length);
1405 return;
1406 }
1407
1408 if (png_crc_finish(png_ptr, 0))
1409 {
1410 png_ptr->num_trans = 0;
1411 return;
1412 }
1413
1414 png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
1415 &(png_ptr->trans_values));
1416}
1417#endif
1418
Patrick Scott5f6bd842010-06-28 16:55:16 -04001419#ifdef PNG_READ_bKGD_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001420void /* PRIVATE */
1421png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1422{
1423 png_size_t truelen;
1424 png_byte buf[6];
1425
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001426 png_debug(1, "in png_handle_bKGD");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001427
1428 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1429 png_error(png_ptr, "Missing IHDR before bKGD");
1430 else if (png_ptr->mode & PNG_HAVE_IDAT)
1431 {
1432 png_warning(png_ptr, "Invalid bKGD after IDAT");
1433 png_crc_finish(png_ptr, length);
1434 return;
1435 }
1436 else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
1437 !(png_ptr->mode & PNG_HAVE_PLTE))
1438 {
1439 png_warning(png_ptr, "Missing PLTE before bKGD");
1440 png_crc_finish(png_ptr, length);
1441 return;
1442 }
1443 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
1444 {
1445 png_warning(png_ptr, "Duplicate bKGD chunk");
1446 png_crc_finish(png_ptr, length);
1447 return;
1448 }
1449
1450 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1451 truelen = 1;
1452 else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
1453 truelen = 6;
1454 else
1455 truelen = 2;
1456
1457 if (length != truelen)
1458 {
1459 png_warning(png_ptr, "Incorrect bKGD chunk length");
1460 png_crc_finish(png_ptr, length);
1461 return;
1462 }
1463
1464 png_crc_read(png_ptr, buf, truelen);
1465 if (png_crc_finish(png_ptr, 0))
1466 return;
1467
1468 /* We convert the index value into RGB components so that we can allow
1469 * arbitrary RGB values for background when we have transparency, and
1470 * so it is easy to determine the RGB values of the background color
1471 * from the info_ptr struct. */
1472 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1473 {
1474 png_ptr->background.index = buf[0];
1475 if (info_ptr && info_ptr->num_palette)
1476 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001477 if (buf[0] >= info_ptr->num_palette)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001478 {
1479 png_warning(png_ptr, "Incorrect bKGD chunk index value");
1480 return;
1481 }
1482 png_ptr->background.red =
1483 (png_uint_16)png_ptr->palette[buf[0]].red;
1484 png_ptr->background.green =
1485 (png_uint_16)png_ptr->palette[buf[0]].green;
1486 png_ptr->background.blue =
1487 (png_uint_16)png_ptr->palette[buf[0]].blue;
1488 }
1489 }
1490 else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
1491 {
1492 png_ptr->background.red =
1493 png_ptr->background.green =
1494 png_ptr->background.blue =
1495 png_ptr->background.gray = png_get_uint_16(buf);
1496 }
1497 else
1498 {
1499 png_ptr->background.red = png_get_uint_16(buf);
1500 png_ptr->background.green = png_get_uint_16(buf + 2);
1501 png_ptr->background.blue = png_get_uint_16(buf + 4);
1502 }
1503
1504 png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
1505}
1506#endif
1507
Patrick Scott5f6bd842010-06-28 16:55:16 -04001508#ifdef PNG_READ_hIST_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001509void /* PRIVATE */
1510png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1511{
1512 unsigned int num, i;
1513 png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
1514
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001515 png_debug(1, "in png_handle_hIST");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001516
1517 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1518 png_error(png_ptr, "Missing IHDR before hIST");
1519 else if (png_ptr->mode & PNG_HAVE_IDAT)
1520 {
1521 png_warning(png_ptr, "Invalid hIST after IDAT");
1522 png_crc_finish(png_ptr, length);
1523 return;
1524 }
1525 else if (!(png_ptr->mode & PNG_HAVE_PLTE))
1526 {
1527 png_warning(png_ptr, "Missing PLTE before hIST");
1528 png_crc_finish(png_ptr, length);
1529 return;
1530 }
1531 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
1532 {
1533 png_warning(png_ptr, "Duplicate hIST chunk");
1534 png_crc_finish(png_ptr, length);
1535 return;
1536 }
1537
1538 num = length / 2 ;
1539 if (num != (unsigned int) png_ptr->num_palette || num >
1540 (unsigned int) PNG_MAX_PALETTE_LENGTH)
1541 {
1542 png_warning(png_ptr, "Incorrect hIST chunk length");
1543 png_crc_finish(png_ptr, length);
1544 return;
1545 }
1546
1547 for (i = 0; i < num; i++)
1548 {
1549 png_byte buf[2];
1550
1551 png_crc_read(png_ptr, buf, 2);
1552 readbuf[i] = png_get_uint_16(buf);
1553 }
1554
1555 if (png_crc_finish(png_ptr, 0))
1556 return;
1557
1558 png_set_hIST(png_ptr, info_ptr, readbuf);
1559}
1560#endif
1561
Patrick Scott5f6bd842010-06-28 16:55:16 -04001562#ifdef PNG_READ_pHYs_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001563void /* PRIVATE */
1564png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1565{
1566 png_byte buf[9];
1567 png_uint_32 res_x, res_y;
1568 int unit_type;
1569
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001570 png_debug(1, "in png_handle_pHYs");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001571
1572 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1573 png_error(png_ptr, "Missing IHDR before pHYs");
1574 else if (png_ptr->mode & PNG_HAVE_IDAT)
1575 {
1576 png_warning(png_ptr, "Invalid pHYs after IDAT");
1577 png_crc_finish(png_ptr, length);
1578 return;
1579 }
1580 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
1581 {
1582 png_warning(png_ptr, "Duplicate pHYs chunk");
1583 png_crc_finish(png_ptr, length);
1584 return;
1585 }
1586
1587 if (length != 9)
1588 {
1589 png_warning(png_ptr, "Incorrect pHYs chunk length");
1590 png_crc_finish(png_ptr, length);
1591 return;
1592 }
1593
1594 png_crc_read(png_ptr, buf, 9);
1595 if (png_crc_finish(png_ptr, 0))
1596 return;
1597
1598 res_x = png_get_uint_32(buf);
1599 res_y = png_get_uint_32(buf + 4);
1600 unit_type = buf[8];
1601 png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
1602}
1603#endif
1604
Patrick Scott5f6bd842010-06-28 16:55:16 -04001605#ifdef PNG_READ_oFFs_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001606void /* PRIVATE */
1607png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1608{
1609 png_byte buf[9];
1610 png_int_32 offset_x, offset_y;
1611 int unit_type;
1612
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001613 png_debug(1, "in png_handle_oFFs");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001614
1615 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1616 png_error(png_ptr, "Missing IHDR before oFFs");
1617 else if (png_ptr->mode & PNG_HAVE_IDAT)
1618 {
1619 png_warning(png_ptr, "Invalid oFFs after IDAT");
1620 png_crc_finish(png_ptr, length);
1621 return;
1622 }
1623 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
1624 {
1625 png_warning(png_ptr, "Duplicate oFFs chunk");
1626 png_crc_finish(png_ptr, length);
1627 return;
1628 }
1629
1630 if (length != 9)
1631 {
1632 png_warning(png_ptr, "Incorrect oFFs chunk length");
1633 png_crc_finish(png_ptr, length);
1634 return;
1635 }
1636
1637 png_crc_read(png_ptr, buf, 9);
1638 if (png_crc_finish(png_ptr, 0))
1639 return;
1640
1641 offset_x = png_get_int_32(buf);
1642 offset_y = png_get_int_32(buf + 4);
1643 unit_type = buf[8];
1644 png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
1645}
1646#endif
1647
Patrick Scott5f6bd842010-06-28 16:55:16 -04001648#ifdef PNG_READ_pCAL_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001649/* Read the pCAL chunk (described in the PNG Extensions document) */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001650void /* PRIVATE */
1651png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1652{
The Android Open Source Project893912b2009-03-03 19:30:05 -08001653 png_int_32 X0, X1;
1654 png_byte type, nparams;
1655 png_charp buf, units, endptr;
1656 png_charpp params;
1657 png_size_t slength;
1658 int i;
1659
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001660 png_debug(1, "in png_handle_pCAL");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001661
1662 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1663 png_error(png_ptr, "Missing IHDR before pCAL");
1664 else if (png_ptr->mode & PNG_HAVE_IDAT)
1665 {
1666 png_warning(png_ptr, "Invalid pCAL after IDAT");
1667 png_crc_finish(png_ptr, length);
1668 return;
1669 }
1670 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
1671 {
1672 png_warning(png_ptr, "Duplicate pCAL chunk");
1673 png_crc_finish(png_ptr, length);
1674 return;
1675 }
1676
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001677 png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)",
The Android Open Source Project893912b2009-03-03 19:30:05 -08001678 length + 1);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001679 png_free(png_ptr, png_ptr->chunkdata);
1680 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1681 if (png_ptr->chunkdata == NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001682 {
1683 png_warning(png_ptr, "No memory for pCAL purpose.");
1684 return;
1685 }
1686 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001687 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001688
1689 if (png_crc_finish(png_ptr, 0))
1690 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001691 png_free(png_ptr, png_ptr->chunkdata);
1692 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001693 return;
1694 }
1695
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001696 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001697
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001698 png_debug(3, "Finding end of pCAL purpose string");
1699 for (buf = png_ptr->chunkdata; *buf; buf++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001700 /* Empty loop */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001701
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001702 endptr = png_ptr->chunkdata + slength;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001703
1704 /* We need to have at least 12 bytes after the purpose string
1705 in order to get the parameter information. */
1706 if (endptr <= buf + 12)
1707 {
1708 png_warning(png_ptr, "Invalid pCAL data");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001709 png_free(png_ptr, png_ptr->chunkdata);
1710 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001711 return;
1712 }
1713
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001714 png_debug(3, "Reading pCAL X0, X1, type, nparams, and units");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001715 X0 = png_get_int_32((png_bytep)buf+1);
1716 X1 = png_get_int_32((png_bytep)buf+5);
1717 type = buf[9];
1718 nparams = buf[10];
1719 units = buf + 11;
1720
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001721 png_debug(3, "Checking pCAL equation type and number of parameters");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001722 /* Check that we have the right number of parameters for known
1723 equation types. */
1724 if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
1725 (type == PNG_EQUATION_BASE_E && nparams != 3) ||
1726 (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
1727 (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
1728 {
1729 png_warning(png_ptr, "Invalid pCAL parameters for equation type");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001730 png_free(png_ptr, png_ptr->chunkdata);
1731 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001732 return;
1733 }
1734 else if (type >= PNG_EQUATION_LAST)
1735 {
1736 png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
1737 }
1738
1739 for (buf = units; *buf; buf++)
1740 /* Empty loop to move past the units string. */ ;
1741
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001742 png_debug(3, "Allocating pCAL parameters array");
1743 params = (png_charpp)png_malloc_warn(png_ptr,
1744 (png_uint_32)(nparams * png_sizeof(png_charp))) ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001745 if (params == NULL)
1746 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001747 png_free(png_ptr, png_ptr->chunkdata);
1748 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001749 png_warning(png_ptr, "No memory for pCAL params.");
1750 return;
1751 }
1752
1753 /* Get pointers to the start of each parameter string. */
1754 for (i = 0; i < (int)nparams; i++)
1755 {
1756 buf++; /* Skip the null string terminator from previous parameter. */
1757
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001758 png_debug1(3, "Reading pCAL parameter %d", i);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001759 for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++)
1760 /* Empty loop to move past each parameter string */ ;
1761
1762 /* Make sure we haven't run out of data yet */
1763 if (buf > endptr)
1764 {
1765 png_warning(png_ptr, "Invalid pCAL data");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001766 png_free(png_ptr, png_ptr->chunkdata);
1767 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001768 png_free(png_ptr, params);
1769 return;
1770 }
1771 }
1772
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001773 png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams,
The Android Open Source Project893912b2009-03-03 19:30:05 -08001774 units, params);
1775
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001776 png_free(png_ptr, png_ptr->chunkdata);
1777 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001778 png_free(png_ptr, params);
1779}
1780#endif
1781
Patrick Scott5f6bd842010-06-28 16:55:16 -04001782#ifdef PNG_READ_sCAL_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001783/* Read the sCAL chunk */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001784void /* PRIVATE */
1785png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1786{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001787 png_charp ep;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001788#ifdef PNG_FLOATING_POINT_SUPPORTED
1789 double width, height;
1790 png_charp vp;
1791#else
1792#ifdef PNG_FIXED_POINT_SUPPORTED
1793 png_charp swidth, sheight;
1794#endif
1795#endif
1796 png_size_t slength;
1797
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001798 png_debug(1, "in png_handle_sCAL");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001799
1800 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1801 png_error(png_ptr, "Missing IHDR before sCAL");
1802 else if (png_ptr->mode & PNG_HAVE_IDAT)
1803 {
1804 png_warning(png_ptr, "Invalid sCAL after IDAT");
1805 png_crc_finish(png_ptr, length);
1806 return;
1807 }
1808 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
1809 {
1810 png_warning(png_ptr, "Duplicate sCAL chunk");
1811 png_crc_finish(png_ptr, length);
1812 return;
1813 }
1814
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001815 png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)",
The Android Open Source Project893912b2009-03-03 19:30:05 -08001816 length + 1);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001817 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
1818 if (png_ptr->chunkdata == NULL)
1819 {
1820 png_warning(png_ptr, "Out of memory while processing sCAL chunk");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001821 png_crc_finish(png_ptr, length);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001822 return;
1823 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001824 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001825 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001826
1827 if (png_crc_finish(png_ptr, 0))
1828 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001829 png_free(png_ptr, png_ptr->chunkdata);
1830 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001831 return;
1832 }
1833
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001834 png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001835
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001836 ep = png_ptr->chunkdata + 1; /* Skip unit byte */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001837
1838#ifdef PNG_FLOATING_POINT_SUPPORTED
1839 width = png_strtod(png_ptr, ep, &vp);
1840 if (*vp)
1841 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001842 png_warning(png_ptr, "malformed width string in sCAL chunk");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001843 png_free(png_ptr, png_ptr->chunkdata);
1844 png_ptr->chunkdata = NULL;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001845 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001846 }
1847#else
1848#ifdef PNG_FIXED_POINT_SUPPORTED
1849 swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1850 if (swidth == NULL)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001851 {
1852 png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001853 png_free(png_ptr, png_ptr->chunkdata);
1854 png_ptr->chunkdata = NULL;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001855 return;
1856 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001857 png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
1858#endif
1859#endif
1860
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001861 for (ep = png_ptr->chunkdata; *ep; ep++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001862 /* Empty loop */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001863 ep++;
1864
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001865 if (png_ptr->chunkdata + slength < ep)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001866 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001867 png_warning(png_ptr, "Truncated sCAL chunk");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001868#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001869 png_free(png_ptr, swidth);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001870#endif
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001871 png_free(png_ptr, png_ptr->chunkdata);
1872 png_ptr->chunkdata = NULL;
1873 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001874 }
1875
1876#ifdef PNG_FLOATING_POINT_SUPPORTED
1877 height = png_strtod(png_ptr, ep, &vp);
1878 if (*vp)
1879 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001880 png_warning(png_ptr, "malformed height string in sCAL chunk");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001881 png_free(png_ptr, png_ptr->chunkdata);
1882 png_ptr->chunkdata = NULL;
1883#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1884 png_free(png_ptr, swidth);
1885#endif
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001886 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001887 }
1888#else
1889#ifdef PNG_FIXED_POINT_SUPPORTED
1890 sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
1891 if (sheight == NULL)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001892 {
1893 png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001894 png_free(png_ptr, png_ptr->chunkdata);
1895 png_ptr->chunkdata = NULL;
1896#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1897 png_free(png_ptr, swidth);
1898#endif
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001899 return;
1900 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001901 png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
1902#endif
1903#endif
1904
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001905 if (png_ptr->chunkdata + slength < ep
The Android Open Source Project893912b2009-03-03 19:30:05 -08001906#ifdef PNG_FLOATING_POINT_SUPPORTED
1907 || width <= 0. || height <= 0.
1908#endif
1909 )
1910 {
1911 png_warning(png_ptr, "Invalid sCAL data");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001912 png_free(png_ptr, png_ptr->chunkdata);
1913 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001914#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1915 png_free(png_ptr, swidth);
1916 png_free(png_ptr, sheight);
1917#endif
1918 return;
1919 }
1920
1921
1922#ifdef PNG_FLOATING_POINT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001923 png_set_sCAL(png_ptr, info_ptr, png_ptr->chunkdata[0], width, height);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001924#else
1925#ifdef PNG_FIXED_POINT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001926 png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], swidth, sheight);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001927#endif
1928#endif
1929
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001930 png_free(png_ptr, png_ptr->chunkdata);
1931 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001932#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
1933 png_free(png_ptr, swidth);
1934 png_free(png_ptr, sheight);
1935#endif
1936}
1937#endif
1938
Patrick Scott5f6bd842010-06-28 16:55:16 -04001939#ifdef PNG_READ_tIME_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001940void /* PRIVATE */
1941png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1942{
1943 png_byte buf[7];
1944 png_time mod_time;
1945
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001946 png_debug(1, "in png_handle_tIME");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001947
1948 if (!(png_ptr->mode & PNG_HAVE_IHDR))
1949 png_error(png_ptr, "Out of place tIME chunk");
1950 else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
1951 {
1952 png_warning(png_ptr, "Duplicate tIME chunk");
1953 png_crc_finish(png_ptr, length);
1954 return;
1955 }
1956
1957 if (png_ptr->mode & PNG_HAVE_IDAT)
1958 png_ptr->mode |= PNG_AFTER_IDAT;
1959
1960 if (length != 7)
1961 {
1962 png_warning(png_ptr, "Incorrect tIME chunk length");
1963 png_crc_finish(png_ptr, length);
1964 return;
1965 }
1966
1967 png_crc_read(png_ptr, buf, 7);
1968 if (png_crc_finish(png_ptr, 0))
1969 return;
1970
1971 mod_time.second = buf[6];
1972 mod_time.minute = buf[5];
1973 mod_time.hour = buf[4];
1974 mod_time.day = buf[3];
1975 mod_time.month = buf[2];
1976 mod_time.year = png_get_uint_16(buf);
1977
1978 png_set_tIME(png_ptr, info_ptr, &mod_time);
1979}
1980#endif
1981
Patrick Scott5f6bd842010-06-28 16:55:16 -04001982#ifdef PNG_READ_tEXt_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001983/* Note: this does not properly handle chunks that are > 64K under DOS */
1984void /* PRIVATE */
1985png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
1986{
1987 png_textp text_ptr;
1988 png_charp key;
1989 png_charp text;
1990 png_uint_32 skip = 0;
1991 png_size_t slength;
1992 int ret;
1993
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001994 png_debug(1, "in png_handle_tEXt");
1995
Patrick Scott5f6bd842010-06-28 16:55:16 -04001996#ifdef PNG_USER_LIMITS_SUPPORTED
1997 if (png_ptr->user_chunk_cache_max != 0)
1998 {
1999 if (png_ptr->user_chunk_cache_max == 1)
2000 {
2001 png_crc_finish(png_ptr, length);
2002 return;
2003 }
2004 if (--png_ptr->user_chunk_cache_max == 1)
2005 {
2006 png_warning(png_ptr, "No space in chunk cache for tEXt");
2007 png_crc_finish(png_ptr, length);
2008 return;
2009 }
2010 }
2011#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002012
2013 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2014 png_error(png_ptr, "Missing IHDR before tEXt");
2015
2016 if (png_ptr->mode & PNG_HAVE_IDAT)
2017 png_ptr->mode |= PNG_AFTER_IDAT;
2018
2019#ifdef PNG_MAX_MALLOC_64K
2020 if (length > (png_uint_32)65535L)
2021 {
2022 png_warning(png_ptr, "tEXt chunk too large to fit in memory");
2023 skip = length - (png_uint_32)65535L;
2024 length = (png_uint_32)65535L;
2025 }
2026#endif
2027
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002028 png_free(png_ptr, png_ptr->chunkdata);
2029
2030 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2031 if (png_ptr->chunkdata == NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002032 {
2033 png_warning(png_ptr, "No memory to process text chunk.");
2034 return;
2035 }
2036 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002037 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002038
2039 if (png_crc_finish(png_ptr, skip))
2040 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002041 png_free(png_ptr, png_ptr->chunkdata);
2042 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002043 return;
2044 }
2045
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002046 key = png_ptr->chunkdata;
2047
The Android Open Source Project893912b2009-03-03 19:30:05 -08002048 key[slength] = 0x00;
2049
2050 for (text = key; *text; text++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002051 /* Empty loop to find end of key */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002052
2053 if (text != key + slength)
2054 text++;
2055
2056 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2057 (png_uint_32)png_sizeof(png_text));
2058 if (text_ptr == NULL)
2059 {
2060 png_warning(png_ptr, "Not enough memory to process text chunk.");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002061 png_free(png_ptr, png_ptr->chunkdata);
2062 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002063 return;
2064 }
2065 text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
2066 text_ptr->key = key;
2067#ifdef PNG_iTXt_SUPPORTED
2068 text_ptr->lang = NULL;
2069 text_ptr->lang_key = NULL;
2070 text_ptr->itxt_length = 0;
2071#endif
2072 text_ptr->text = text;
2073 text_ptr->text_length = png_strlen(text);
2074
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002075 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002076
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002077 png_free(png_ptr, png_ptr->chunkdata);
2078 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002079 png_free(png_ptr, text_ptr);
2080 if (ret)
2081 png_warning(png_ptr, "Insufficient memory to process text chunk.");
2082}
2083#endif
2084
Patrick Scott5f6bd842010-06-28 16:55:16 -04002085#ifdef PNG_READ_zTXt_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002086/* Note: this does not correctly handle chunks that are > 64K under DOS */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002087void /* PRIVATE */
2088png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2089{
2090 png_textp text_ptr;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002091 png_charp text;
2092 int comp_type;
2093 int ret;
2094 png_size_t slength, prefix_len, data_len;
2095
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002096 png_debug(1, "in png_handle_zTXt");
2097
Patrick Scott5f6bd842010-06-28 16:55:16 -04002098#ifdef PNG_USER_LIMITS_SUPPORTED
2099 if (png_ptr->user_chunk_cache_max != 0)
2100 {
2101 if (png_ptr->user_chunk_cache_max == 1)
2102 {
2103 png_crc_finish(png_ptr, length);
2104 return;
2105 }
2106 if (--png_ptr->user_chunk_cache_max == 1)
2107 {
2108 png_warning(png_ptr, "No space in chunk cache for zTXt");
2109 png_crc_finish(png_ptr, length);
2110 return;
2111 }
2112 }
2113#endif
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002114
The Android Open Source Project893912b2009-03-03 19:30:05 -08002115 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2116 png_error(png_ptr, "Missing IHDR before zTXt");
2117
2118 if (png_ptr->mode & PNG_HAVE_IDAT)
2119 png_ptr->mode |= PNG_AFTER_IDAT;
2120
2121#ifdef PNG_MAX_MALLOC_64K
2122 /* We will no doubt have problems with chunks even half this size, but
2123 there is no hard and fast rule to tell us where to stop. */
2124 if (length > (png_uint_32)65535L)
2125 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002126 png_warning(png_ptr, "zTXt chunk too large to fit in memory");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002127 png_crc_finish(png_ptr, length);
2128 return;
2129 }
2130#endif
2131
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002132 png_free(png_ptr, png_ptr->chunkdata);
2133 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2134 if (png_ptr->chunkdata == NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002135 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002136 png_warning(png_ptr, "Out of memory processing zTXt chunk.");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002137 return;
2138 }
2139 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002140 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002141 if (png_crc_finish(png_ptr, 0))
2142 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002143 png_free(png_ptr, png_ptr->chunkdata);
2144 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002145 return;
2146 }
2147
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002148 png_ptr->chunkdata[slength] = 0x00;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002149
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002150 for (text = png_ptr->chunkdata; *text; text++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002151 /* Empty loop */ ;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002152
2153 /* zTXt must have some text after the chunkdataword */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002154 if (text >= png_ptr->chunkdata + slength - 2)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002155 {
2156 png_warning(png_ptr, "Truncated zTXt chunk");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002157 png_free(png_ptr, png_ptr->chunkdata);
2158 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002159 return;
2160 }
2161 else
2162 {
2163 comp_type = *(++text);
2164 if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
2165 {
2166 png_warning(png_ptr, "Unknown compression type in zTXt chunk");
2167 comp_type = PNG_TEXT_COMPRESSION_zTXt;
2168 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002169 text++; /* Skip the compression_method byte */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002170 }
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002171 prefix_len = text - png_ptr->chunkdata;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002172
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002173 png_decompress_chunk(png_ptr, comp_type,
2174 (png_size_t)length, prefix_len, &data_len);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002175
2176 text_ptr = (png_textp)png_malloc_warn(png_ptr,
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002177 (png_uint_32)png_sizeof(png_text));
The Android Open Source Project893912b2009-03-03 19:30:05 -08002178 if (text_ptr == NULL)
2179 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002180 png_warning(png_ptr, "Not enough memory to process zTXt chunk.");
2181 png_free(png_ptr, png_ptr->chunkdata);
2182 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002183 return;
2184 }
2185 text_ptr->compression = comp_type;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002186 text_ptr->key = png_ptr->chunkdata;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002187#ifdef PNG_iTXt_SUPPORTED
2188 text_ptr->lang = NULL;
2189 text_ptr->lang_key = NULL;
2190 text_ptr->itxt_length = 0;
2191#endif
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002192 text_ptr->text = png_ptr->chunkdata + prefix_len;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002193 text_ptr->text_length = data_len;
2194
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002195 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002196
2197 png_free(png_ptr, text_ptr);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002198 png_free(png_ptr, png_ptr->chunkdata);
2199 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002200 if (ret)
2201 png_error(png_ptr, "Insufficient memory to store zTXt chunk.");
2202}
2203#endif
2204
Patrick Scott5f6bd842010-06-28 16:55:16 -04002205#ifdef PNG_READ_iTXt_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002206/* Note: this does not correctly handle chunks that are > 64K under DOS */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002207void /* PRIVATE */
2208png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2209{
2210 png_textp text_ptr;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002211 png_charp key, lang, text, lang_key;
2212 int comp_flag;
2213 int comp_type = 0;
2214 int ret;
2215 png_size_t slength, prefix_len, data_len;
2216
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002217 png_debug(1, "in png_handle_iTXt");
2218
Patrick Scott5f6bd842010-06-28 16:55:16 -04002219#ifdef PNG_USER_LIMITS_SUPPORTED
2220 if (png_ptr->user_chunk_cache_max != 0)
2221 {
2222 if (png_ptr->user_chunk_cache_max == 1)
2223 {
2224 png_crc_finish(png_ptr, length);
2225 return;
2226 }
2227 if (--png_ptr->user_chunk_cache_max == 1)
2228 {
2229 png_warning(png_ptr, "No space in chunk cache for iTXt");
2230 png_crc_finish(png_ptr, length);
2231 return;
2232 }
2233 }
2234#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002235
2236 if (!(png_ptr->mode & PNG_HAVE_IHDR))
2237 png_error(png_ptr, "Missing IHDR before iTXt");
2238
2239 if (png_ptr->mode & PNG_HAVE_IDAT)
2240 png_ptr->mode |= PNG_AFTER_IDAT;
2241
2242#ifdef PNG_MAX_MALLOC_64K
2243 /* We will no doubt have problems with chunks even half this size, but
2244 there is no hard and fast rule to tell us where to stop. */
2245 if (length > (png_uint_32)65535L)
2246 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002247 png_warning(png_ptr, "iTXt chunk too large to fit in memory");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002248 png_crc_finish(png_ptr, length);
2249 return;
2250 }
2251#endif
2252
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002253 png_free(png_ptr, png_ptr->chunkdata);
2254 png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
2255 if (png_ptr->chunkdata == NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002256 {
2257 png_warning(png_ptr, "No memory to process iTXt chunk.");
2258 return;
2259 }
2260 slength = (png_size_t)length;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002261 png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002262 if (png_crc_finish(png_ptr, 0))
2263 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002264 png_free(png_ptr, png_ptr->chunkdata);
2265 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002266 return;
2267 }
2268
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002269 png_ptr->chunkdata[slength] = 0x00;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002270
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002271 for (lang = png_ptr->chunkdata; *lang; lang++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002272 /* Empty loop */ ;
2273 lang++; /* Skip NUL separator */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002274
2275 /* iTXt must have a language tag (possibly empty), two compression bytes,
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002276 * translated keyword (possibly empty), and possibly some text after the
2277 * keyword
2278 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002279
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002280 if (lang >= png_ptr->chunkdata + slength - 3)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002281 {
2282 png_warning(png_ptr, "Truncated iTXt chunk");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002283 png_free(png_ptr, png_ptr->chunkdata);
2284 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002285 return;
2286 }
2287 else
2288 {
2289 comp_flag = *lang++;
2290 comp_type = *lang++;
2291 }
2292
2293 for (lang_key = lang; *lang_key; lang_key++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002294 /* Empty loop */ ;
2295 lang_key++; /* Skip NUL separator */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002296
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002297 if (lang_key >= png_ptr->chunkdata + slength)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002298 {
2299 png_warning(png_ptr, "Truncated iTXt chunk");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002300 png_free(png_ptr, png_ptr->chunkdata);
2301 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002302 return;
2303 }
2304
2305 for (text = lang_key; *text; text++)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002306 /* Empty loop */ ;
2307 text++; /* Skip NUL separator */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002308 if (text >= png_ptr->chunkdata + slength)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002309 {
2310 png_warning(png_ptr, "Malformed iTXt chunk");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002311 png_free(png_ptr, png_ptr->chunkdata);
2312 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002313 return;
2314 }
2315
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002316 prefix_len = text - png_ptr->chunkdata;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002317
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002318 key=png_ptr->chunkdata;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002319 if (comp_flag)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002320 png_decompress_chunk(png_ptr, comp_type,
2321 (size_t)length, prefix_len, &data_len);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002322 else
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002323 data_len = png_strlen(png_ptr->chunkdata + prefix_len);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002324 text_ptr = (png_textp)png_malloc_warn(png_ptr,
2325 (png_uint_32)png_sizeof(png_text));
2326 if (text_ptr == NULL)
2327 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002328 png_warning(png_ptr, "Not enough memory to process iTXt chunk.");
2329 png_free(png_ptr, png_ptr->chunkdata);
2330 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002331 return;
2332 }
2333 text_ptr->compression = (int)comp_flag + 1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002334 text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
2335 text_ptr->lang = png_ptr->chunkdata + (lang - key);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002336 text_ptr->itxt_length = data_len;
2337 text_ptr->text_length = 0;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002338 text_ptr->key = png_ptr->chunkdata;
2339 text_ptr->text = png_ptr->chunkdata + prefix_len;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002340
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002341 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002342
2343 png_free(png_ptr, text_ptr);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002344 png_free(png_ptr, png_ptr->chunkdata);
2345 png_ptr->chunkdata = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002346 if (ret)
2347 png_error(png_ptr, "Insufficient memory to store iTXt chunk.");
2348}
2349#endif
2350
2351/* This function is called when we haven't found a handler for a
2352 chunk. If there isn't a problem with the chunk itself (ie bad
2353 chunk name, CRC, or a critical chunk), the chunk is silently ignored
2354 -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
2355 case it will be saved away to be written out later. */
2356void /* PRIVATE */
2357png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
2358{
2359 png_uint_32 skip = 0;
2360
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002361 png_debug(1, "in png_handle_unknown");
2362
Patrick Scott5f6bd842010-06-28 16:55:16 -04002363#ifdef PNG_USER_LIMITS_SUPPORTED
2364 if (png_ptr->user_chunk_cache_max != 0)
2365 {
2366 if (png_ptr->user_chunk_cache_max == 1)
2367 {
2368 png_crc_finish(png_ptr, length);
2369 return;
2370 }
2371 if (--png_ptr->user_chunk_cache_max == 1)
2372 {
2373 png_warning(png_ptr, "No space in chunk cache for unknown chunk");
2374 png_crc_finish(png_ptr, length);
2375 return;
2376 }
2377 }
2378#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002379
2380 if (png_ptr->mode & PNG_HAVE_IDAT)
2381 {
2382#ifdef PNG_USE_LOCAL_ARRAYS
2383 PNG_CONST PNG_IDAT;
2384#endif
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002385 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002386 png_ptr->mode |= PNG_AFTER_IDAT;
2387 }
2388
The Android Open Source Project893912b2009-03-03 19:30:05 -08002389 if (!(png_ptr->chunk_name[0] & 0x20))
2390 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04002391#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002392 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
The Android Open Source Project893912b2009-03-03 19:30:05 -08002393 PNG_HANDLE_CHUNK_ALWAYS
Patrick Scott5f6bd842010-06-28 16:55:16 -04002394#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002395 && png_ptr->read_user_chunk_fn == NULL
2396#endif
2397 )
2398#endif
2399 png_chunk_error(png_ptr, "unknown critical chunk");
2400 }
2401
Patrick Scott5f6bd842010-06-28 16:55:16 -04002402#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002403 if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
Patrick Scott5f6bd842010-06-28 16:55:16 -04002404#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002405 || (png_ptr->read_user_chunk_fn != NULL)
2406#endif
2407 )
The Android Open Source Project893912b2009-03-03 19:30:05 -08002408 {
2409#ifdef PNG_MAX_MALLOC_64K
2410 if (length > (png_uint_32)65535L)
2411 {
2412 png_warning(png_ptr, "unknown chunk too large to fit in memory");
2413 skip = length - (png_uint_32)65535L;
2414 length = (png_uint_32)65535L;
2415 }
2416#endif
2417 png_memcpy((png_charp)png_ptr->unknown_chunk.name,
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002418 (png_charp)png_ptr->chunk_name,
The Android Open Source Project893912b2009-03-03 19:30:05 -08002419 png_sizeof(png_ptr->unknown_chunk.name));
Patrick Scott5f6bd842010-06-28 16:55:16 -04002420 png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
2421 = '\0';
The Android Open Source Project893912b2009-03-03 19:30:05 -08002422 png_ptr->unknown_chunk.size = (png_size_t)length;
2423 if (length == 0)
2424 png_ptr->unknown_chunk.data = NULL;
2425 else
2426 {
2427 png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
2428 png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
2429 }
Patrick Scott5f6bd842010-06-28 16:55:16 -04002430#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002431 if (png_ptr->read_user_chunk_fn != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002432 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002433 /* Callback to user unknown chunk handler */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002434 int ret;
2435 ret = (*(png_ptr->read_user_chunk_fn))
2436 (png_ptr, &png_ptr->unknown_chunk);
2437 if (ret < 0)
2438 png_chunk_error(png_ptr, "error in user chunk");
2439 if (ret == 0)
2440 {
2441 if (!(png_ptr->chunk_name[0] & 0x20))
Patrick Scott5f6bd842010-06-28 16:55:16 -04002442#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002443 if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
The Android Open Source Project893912b2009-03-03 19:30:05 -08002444 PNG_HANDLE_CHUNK_ALWAYS)
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002445#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002446 png_chunk_error(png_ptr, "unknown critical chunk");
2447 png_set_unknown_chunks(png_ptr, info_ptr,
2448 &png_ptr->unknown_chunk, 1);
2449 }
2450 }
2451 else
2452#endif
2453 png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
2454 png_free(png_ptr, png_ptr->unknown_chunk.data);
2455 png_ptr->unknown_chunk.data = NULL;
2456 }
2457 else
2458#endif
2459 skip = length;
2460
2461 png_crc_finish(png_ptr, skip);
2462
Patrick Scott5f6bd842010-06-28 16:55:16 -04002463#ifndef PNG_READ_USER_CHUNKS_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002464 info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002465#endif
2466}
2467
2468/* This function is called to verify that a chunk name is valid.
2469 This function can't have the "critical chunk check" incorporated
2470 into it, since in the future we will need to be able to call user
2471 functions to handle unknown critical chunks after we check that
2472 the chunk name itself is valid. */
2473
2474#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
2475
2476void /* PRIVATE */
2477png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
2478{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002479 png_debug(1, "in png_check_chunk_name");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002480 if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
2481 isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
2482 {
2483 png_chunk_error(png_ptr, "invalid chunk type");
2484 }
2485}
2486
2487/* Combines the row recently read in with the existing pixels in the
2488 row. This routine takes care of alpha and transparency if requested.
2489 This routine also handles the two methods of progressive display
2490 of interlaced images, depending on the mask value.
2491 The mask value describes which pixels are to be combined with
2492 the row. The pattern always repeats every 8 pixels, so just 8
2493 bits are needed. A one indicates the pixel is to be combined,
2494 a zero indicates the pixel is to be skipped. This is in addition
2495 to any alpha or transparency value associated with the pixel. If
2496 you want all pixels to be combined, pass 0xff (255) in mask. */
2497
2498void /* PRIVATE */
2499png_combine_row(png_structp png_ptr, png_bytep row, int mask)
2500{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002501 png_debug(1, "in png_combine_row");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002502 if (mask == 0xff)
2503 {
2504 png_memcpy(row, png_ptr->row_buf + 1,
2505 PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
2506 }
2507 else
2508 {
2509 switch (png_ptr->row_info.pixel_depth)
2510 {
2511 case 1:
2512 {
2513 png_bytep sp = png_ptr->row_buf + 1;
2514 png_bytep dp = row;
2515 int s_inc, s_start, s_end;
2516 int m = 0x80;
2517 int shift;
2518 png_uint_32 i;
2519 png_uint_32 row_width = png_ptr->width;
2520
Patrick Scott5f6bd842010-06-28 16:55:16 -04002521#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002522 if (png_ptr->transformations & PNG_PACKSWAP)
2523 {
2524 s_start = 0;
2525 s_end = 7;
2526 s_inc = 1;
2527 }
2528 else
2529#endif
2530 {
2531 s_start = 7;
2532 s_end = 0;
2533 s_inc = -1;
2534 }
2535
2536 shift = s_start;
2537
2538 for (i = 0; i < row_width; i++)
2539 {
2540 if (m & mask)
2541 {
2542 int value;
2543
2544 value = (*sp >> shift) & 0x01;
2545 *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
2546 *dp |= (png_byte)(value << shift);
2547 }
2548
2549 if (shift == s_end)
2550 {
2551 shift = s_start;
2552 sp++;
2553 dp++;
2554 }
2555 else
2556 shift += s_inc;
2557
2558 if (m == 1)
2559 m = 0x80;
2560 else
2561 m >>= 1;
2562 }
2563 break;
2564 }
2565 case 2:
2566 {
2567 png_bytep sp = png_ptr->row_buf + 1;
2568 png_bytep dp = row;
2569 int s_start, s_end, s_inc;
2570 int m = 0x80;
2571 int shift;
2572 png_uint_32 i;
2573 png_uint_32 row_width = png_ptr->width;
2574 int value;
2575
Patrick Scott5f6bd842010-06-28 16:55:16 -04002576#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002577 if (png_ptr->transformations & PNG_PACKSWAP)
2578 {
2579 s_start = 0;
2580 s_end = 6;
2581 s_inc = 2;
2582 }
2583 else
2584#endif
2585 {
2586 s_start = 6;
2587 s_end = 0;
2588 s_inc = -2;
2589 }
2590
2591 shift = s_start;
2592
2593 for (i = 0; i < row_width; i++)
2594 {
2595 if (m & mask)
2596 {
2597 value = (*sp >> shift) & 0x03;
2598 *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
2599 *dp |= (png_byte)(value << shift);
2600 }
2601
2602 if (shift == s_end)
2603 {
2604 shift = s_start;
2605 sp++;
2606 dp++;
2607 }
2608 else
2609 shift += s_inc;
2610 if (m == 1)
2611 m = 0x80;
2612 else
2613 m >>= 1;
2614 }
2615 break;
2616 }
2617 case 4:
2618 {
2619 png_bytep sp = png_ptr->row_buf + 1;
2620 png_bytep dp = row;
2621 int s_start, s_end, s_inc;
2622 int m = 0x80;
2623 int shift;
2624 png_uint_32 i;
2625 png_uint_32 row_width = png_ptr->width;
2626 int value;
2627
Patrick Scott5f6bd842010-06-28 16:55:16 -04002628#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002629 if (png_ptr->transformations & PNG_PACKSWAP)
2630 {
2631 s_start = 0;
2632 s_end = 4;
2633 s_inc = 4;
2634 }
2635 else
2636#endif
2637 {
2638 s_start = 4;
2639 s_end = 0;
2640 s_inc = -4;
2641 }
2642 shift = s_start;
2643
2644 for (i = 0; i < row_width; i++)
2645 {
2646 if (m & mask)
2647 {
2648 value = (*sp >> shift) & 0xf;
2649 *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
2650 *dp |= (png_byte)(value << shift);
2651 }
2652
2653 if (shift == s_end)
2654 {
2655 shift = s_start;
2656 sp++;
2657 dp++;
2658 }
2659 else
2660 shift += s_inc;
2661 if (m == 1)
2662 m = 0x80;
2663 else
2664 m >>= 1;
2665 }
2666 break;
2667 }
2668 default:
2669 {
2670 png_bytep sp = png_ptr->row_buf + 1;
2671 png_bytep dp = row;
2672 png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
2673 png_uint_32 i;
2674 png_uint_32 row_width = png_ptr->width;
2675 png_byte m = 0x80;
2676
2677
2678 for (i = 0; i < row_width; i++)
2679 {
2680 if (m & mask)
2681 {
2682 png_memcpy(dp, sp, pixel_bytes);
2683 }
2684
2685 sp += pixel_bytes;
2686 dp += pixel_bytes;
2687
2688 if (m == 1)
2689 m = 0x80;
2690 else
2691 m >>= 1;
2692 }
2693 break;
2694 }
2695 }
2696 }
2697}
2698
2699#ifdef PNG_READ_INTERLACING_SUPPORTED
2700/* OLD pre-1.0.9 interface:
2701void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
2702 png_uint_32 transformations)
2703 */
2704void /* PRIVATE */
2705png_do_read_interlace(png_structp png_ptr)
2706{
2707 png_row_infop row_info = &(png_ptr->row_info);
2708 png_bytep row = png_ptr->row_buf + 1;
2709 int pass = png_ptr->pass;
2710 png_uint_32 transformations = png_ptr->transformations;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002711 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
2712 /* Offset to next interlace block */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002713 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
The Android Open Source Project893912b2009-03-03 19:30:05 -08002714
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002715 png_debug(1, "in png_do_read_interlace");
The Android Open Source Project893912b2009-03-03 19:30:05 -08002716 if (row != NULL && row_info != NULL)
2717 {
2718 png_uint_32 final_width;
2719
2720 final_width = row_info->width * png_pass_inc[pass];
2721
2722 switch (row_info->pixel_depth)
2723 {
2724 case 1:
2725 {
2726 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
2727 png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
2728 int sshift, dshift;
2729 int s_start, s_end, s_inc;
2730 int jstop = png_pass_inc[pass];
2731 png_byte v;
2732 png_uint_32 i;
2733 int j;
2734
Patrick Scott5f6bd842010-06-28 16:55:16 -04002735#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002736 if (transformations & PNG_PACKSWAP)
2737 {
2738 sshift = (int)((row_info->width + 7) & 0x07);
2739 dshift = (int)((final_width + 7) & 0x07);
2740 s_start = 7;
2741 s_end = 0;
2742 s_inc = -1;
2743 }
2744 else
2745#endif
2746 {
2747 sshift = 7 - (int)((row_info->width + 7) & 0x07);
2748 dshift = 7 - (int)((final_width + 7) & 0x07);
2749 s_start = 0;
2750 s_end = 7;
2751 s_inc = 1;
2752 }
2753
2754 for (i = 0; i < row_info->width; i++)
2755 {
2756 v = (png_byte)((*sp >> sshift) & 0x01);
2757 for (j = 0; j < jstop; j++)
2758 {
2759 *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
2760 *dp |= (png_byte)(v << dshift);
2761 if (dshift == s_end)
2762 {
2763 dshift = s_start;
2764 dp--;
2765 }
2766 else
2767 dshift += s_inc;
2768 }
2769 if (sshift == s_end)
2770 {
2771 sshift = s_start;
2772 sp--;
2773 }
2774 else
2775 sshift += s_inc;
2776 }
2777 break;
2778 }
2779 case 2:
2780 {
2781 png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
2782 png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
2783 int sshift, dshift;
2784 int s_start, s_end, s_inc;
2785 int jstop = png_pass_inc[pass];
2786 png_uint_32 i;
2787
Patrick Scott5f6bd842010-06-28 16:55:16 -04002788#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002789 if (transformations & PNG_PACKSWAP)
2790 {
2791 sshift = (int)(((row_info->width + 3) & 0x03) << 1);
2792 dshift = (int)(((final_width + 3) & 0x03) << 1);
2793 s_start = 6;
2794 s_end = 0;
2795 s_inc = -2;
2796 }
2797 else
2798#endif
2799 {
2800 sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
2801 dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
2802 s_start = 0;
2803 s_end = 6;
2804 s_inc = 2;
2805 }
2806
2807 for (i = 0; i < row_info->width; i++)
2808 {
2809 png_byte v;
2810 int j;
2811
2812 v = (png_byte)((*sp >> sshift) & 0x03);
2813 for (j = 0; j < jstop; j++)
2814 {
2815 *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
2816 *dp |= (png_byte)(v << dshift);
2817 if (dshift == s_end)
2818 {
2819 dshift = s_start;
2820 dp--;
2821 }
2822 else
2823 dshift += s_inc;
2824 }
2825 if (sshift == s_end)
2826 {
2827 sshift = s_start;
2828 sp--;
2829 }
2830 else
2831 sshift += s_inc;
2832 }
2833 break;
2834 }
2835 case 4:
2836 {
2837 png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
2838 png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
2839 int sshift, dshift;
2840 int s_start, s_end, s_inc;
2841 png_uint_32 i;
2842 int jstop = png_pass_inc[pass];
2843
Patrick Scott5f6bd842010-06-28 16:55:16 -04002844#ifdef PNG_READ_PACKSWAP_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002845 if (transformations & PNG_PACKSWAP)
2846 {
2847 sshift = (int)(((row_info->width + 1) & 0x01) << 2);
2848 dshift = (int)(((final_width + 1) & 0x01) << 2);
2849 s_start = 4;
2850 s_end = 0;
2851 s_inc = -4;
2852 }
2853 else
2854#endif
2855 {
2856 sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
2857 dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
2858 s_start = 0;
2859 s_end = 4;
2860 s_inc = 4;
2861 }
2862
2863 for (i = 0; i < row_info->width; i++)
2864 {
2865 png_byte v = (png_byte)((*sp >> sshift) & 0xf);
2866 int j;
2867
2868 for (j = 0; j < jstop; j++)
2869 {
2870 *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
2871 *dp |= (png_byte)(v << dshift);
2872 if (dshift == s_end)
2873 {
2874 dshift = s_start;
2875 dp--;
2876 }
2877 else
2878 dshift += s_inc;
2879 }
2880 if (sshift == s_end)
2881 {
2882 sshift = s_start;
2883 sp--;
2884 }
2885 else
2886 sshift += s_inc;
2887 }
2888 break;
2889 }
2890 default:
2891 {
2892 png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
Patrick Scott5f6bd842010-06-28 16:55:16 -04002893 png_bytep sp = row + (png_size_t)(row_info->width - 1)
2894 * pixel_bytes;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002895 png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
2896
2897 int jstop = png_pass_inc[pass];
2898 png_uint_32 i;
2899
2900 for (i = 0; i < row_info->width; i++)
2901 {
2902 png_byte v[8];
2903 int j;
2904
2905 png_memcpy(v, sp, pixel_bytes);
2906 for (j = 0; j < jstop; j++)
2907 {
2908 png_memcpy(dp, v, pixel_bytes);
2909 dp -= pixel_bytes;
2910 }
2911 sp -= pixel_bytes;
2912 }
2913 break;
2914 }
2915 }
2916 row_info->width = final_width;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002917 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002918 }
Patrick Scott5f6bd842010-06-28 16:55:16 -04002919#ifndef PNG_READ_PACKSWAP_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002920 transformations = transformations; /* Silence compiler warning */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002921#endif
2922}
2923#endif /* PNG_READ_INTERLACING_SUPPORTED */
2924
2925void /* PRIVATE */
2926png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
2927 png_bytep prev_row, int filter)
2928{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002929 png_debug(1, "in png_read_filter_row");
2930 png_debug2(2, "row = %lu, filter = %d", png_ptr->row_number, filter);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002931 switch (filter)
2932 {
2933 case PNG_FILTER_VALUE_NONE:
2934 break;
2935 case PNG_FILTER_VALUE_SUB:
2936 {
2937 png_uint_32 i;
2938 png_uint_32 istop = row_info->rowbytes;
2939 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
2940 png_bytep rp = row + bpp;
2941 png_bytep lp = row;
2942
2943 for (i = bpp; i < istop; i++)
2944 {
2945 *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
2946 rp++;
2947 }
2948 break;
2949 }
2950 case PNG_FILTER_VALUE_UP:
2951 {
2952 png_uint_32 i;
2953 png_uint_32 istop = row_info->rowbytes;
2954 png_bytep rp = row;
2955 png_bytep pp = prev_row;
2956
2957 for (i = 0; i < istop; i++)
2958 {
2959 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
2960 rp++;
2961 }
2962 break;
2963 }
2964 case PNG_FILTER_VALUE_AVG:
2965 {
2966 png_uint_32 i;
2967 png_bytep rp = row;
2968 png_bytep pp = prev_row;
2969 png_bytep lp = row;
2970 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
2971 png_uint_32 istop = row_info->rowbytes - bpp;
2972
2973 for (i = 0; i < bpp; i++)
2974 {
2975 *rp = (png_byte)(((int)(*rp) +
2976 ((int)(*pp++) / 2 )) & 0xff);
2977 rp++;
2978 }
2979
2980 for (i = 0; i < istop; i++)
2981 {
2982 *rp = (png_byte)(((int)(*rp) +
2983 (int)(*pp++ + *lp++) / 2 ) & 0xff);
2984 rp++;
2985 }
2986 break;
2987 }
2988 case PNG_FILTER_VALUE_PAETH:
2989 {
2990 png_uint_32 i;
2991 png_bytep rp = row;
2992 png_bytep pp = prev_row;
2993 png_bytep lp = row;
2994 png_bytep cp = prev_row;
2995 png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
2996 png_uint_32 istop=row_info->rowbytes - bpp;
2997
2998 for (i = 0; i < bpp; i++)
2999 {
3000 *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
3001 rp++;
3002 }
3003
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003004 for (i = 0; i < istop; i++) /* Use leftover rp,pp */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003005 {
3006 int a, b, c, pa, pb, pc, p;
3007
3008 a = *lp++;
3009 b = *pp++;
3010 c = *cp++;
3011
3012 p = b - c;
3013 pc = a - c;
3014
3015#ifdef PNG_USE_ABS
3016 pa = abs(p);
3017 pb = abs(pc);
3018 pc = abs(p + pc);
3019#else
3020 pa = p < 0 ? -p : p;
3021 pb = pc < 0 ? -pc : pc;
3022 pc = (p + pc) < 0 ? -(p + pc) : p + pc;
3023#endif
3024
3025 /*
3026 if (pa <= pb && pa <= pc)
3027 p = a;
3028 else if (pb <= pc)
3029 p = b;
3030 else
3031 p = c;
3032 */
3033
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003034 p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003035
3036 *rp = (png_byte)(((int)(*rp) + p) & 0xff);
3037 rp++;
3038 }
3039 break;
3040 }
3041 default:
3042 png_warning(png_ptr, "Ignoring bad adaptive filter type");
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003043 *row = 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003044 break;
3045 }
3046}
3047
Patrick Scott5f6bd842010-06-28 16:55:16 -04003048#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003049void /* PRIVATE */
3050png_read_finish_row(png_structp png_ptr)
3051{
The Android Open Source Project893912b2009-03-03 19:30:05 -08003052#ifdef PNG_READ_INTERLACING_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003053 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003054
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003055 /* Start of interlace block */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003056 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
3057
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003058 /* Offset to next interlace block */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003059 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
3060
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003061 /* Start of interlace block in the y direction */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003062 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
3063
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003064 /* Offset to next interlace block in the y direction */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003065 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3066#endif /* PNG_READ_INTERLACING_SUPPORTED */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003067
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003068 png_debug(1, "in png_read_finish_row");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003069 png_ptr->row_number++;
3070 if (png_ptr->row_number < png_ptr->num_rows)
3071 return;
3072
3073#ifdef PNG_READ_INTERLACING_SUPPORTED
3074 if (png_ptr->interlaced)
3075 {
3076 png_ptr->row_number = 0;
3077 png_memset_check(png_ptr, png_ptr->prev_row, 0,
3078 png_ptr->rowbytes + 1);
3079 do
3080 {
3081 png_ptr->pass++;
3082 if (png_ptr->pass >= 7)
3083 break;
3084 png_ptr->iwidth = (png_ptr->width +
3085 png_pass_inc[png_ptr->pass] - 1 -
3086 png_pass_start[png_ptr->pass]) /
3087 png_pass_inc[png_ptr->pass];
3088
The Android Open Source Project893912b2009-03-03 19:30:05 -08003089 if (!(png_ptr->transformations & PNG_INTERLACE))
3090 {
3091 png_ptr->num_rows = (png_ptr->height +
3092 png_pass_yinc[png_ptr->pass] - 1 -
3093 png_pass_ystart[png_ptr->pass]) /
3094 png_pass_yinc[png_ptr->pass];
3095 if (!(png_ptr->num_rows))
3096 continue;
3097 }
3098 else /* if (png_ptr->transformations & PNG_INTERLACE) */
3099 break;
3100 } while (png_ptr->iwidth == 0);
3101
3102 if (png_ptr->pass < 7)
3103 return;
3104 }
3105#endif /* PNG_READ_INTERLACING_SUPPORTED */
3106
3107 if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
3108 {
3109#ifdef PNG_USE_LOCAL_ARRAYS
3110 PNG_CONST PNG_IDAT;
3111#endif
3112 char extra;
3113 int ret;
3114
3115 png_ptr->zstream.next_out = (Byte *)&extra;
3116 png_ptr->zstream.avail_out = (uInt)1;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003117 for (;;)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003118 {
3119 if (!(png_ptr->zstream.avail_in))
3120 {
3121 while (!png_ptr->idat_size)
3122 {
3123 png_byte chunk_length[4];
3124
3125 png_crc_finish(png_ptr, 0);
3126
3127 png_read_data(png_ptr, chunk_length, 4);
3128 png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
3129 png_reset_crc(png_ptr);
3130 png_crc_read(png_ptr, png_ptr->chunk_name, 4);
3131 if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
3132 png_error(png_ptr, "Not enough image data");
3133
3134 }
3135 png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
3136 png_ptr->zstream.next_in = png_ptr->zbuf;
3137 if (png_ptr->zbuf_size > png_ptr->idat_size)
3138 png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
3139 png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
3140 png_ptr->idat_size -= png_ptr->zstream.avail_in;
3141 }
3142 ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
3143 if (ret == Z_STREAM_END)
3144 {
3145 if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
3146 png_ptr->idat_size)
Patrick Scott5f6bd842010-06-28 16:55:16 -04003147 png_warning(png_ptr, "Extra compressed data.");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003148 png_ptr->mode |= PNG_AFTER_IDAT;
3149 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3150 break;
3151 }
3152 if (ret != Z_OK)
3153 png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
3154 "Decompression Error");
3155
3156 if (!(png_ptr->zstream.avail_out))
3157 {
3158 png_warning(png_ptr, "Extra compressed data.");
3159 png_ptr->mode |= PNG_AFTER_IDAT;
3160 png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
3161 break;
3162 }
3163
3164 }
3165 png_ptr->zstream.avail_out = 0;
3166 }
3167
3168 if (png_ptr->idat_size || png_ptr->zstream.avail_in)
Patrick Scott5f6bd842010-06-28 16:55:16 -04003169 png_warning(png_ptr, "Extra compression data.");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003170
3171 inflateReset(&png_ptr->zstream);
3172
3173 png_ptr->mode |= PNG_AFTER_IDAT;
3174}
Patrick Scott5f6bd842010-06-28 16:55:16 -04003175#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003176
3177void /* PRIVATE */
3178png_read_start_row(png_structp png_ptr)
3179{
The Android Open Source Project893912b2009-03-03 19:30:05 -08003180#ifdef PNG_READ_INTERLACING_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003181 /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003182
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003183 /* Start of interlace block */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003184 PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
3185
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003186 /* Offset to next interlace block */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003187 PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
3188
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003189 /* Start of interlace block in the y direction */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003190 PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
3191
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003192 /* Offset to next interlace block in the y direction */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003193 PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
3194#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08003195
3196 int max_pixel_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003197 png_size_t row_bytes;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003198
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003199 png_debug(1, "in png_read_start_row");
The Android Open Source Project893912b2009-03-03 19:30:05 -08003200 png_ptr->zstream.avail_in = 0;
3201 png_init_read_transformations(png_ptr);
3202#ifdef PNG_READ_INTERLACING_SUPPORTED
3203 if (png_ptr->interlaced)
3204 {
3205 if (!(png_ptr->transformations & PNG_INTERLACE))
3206 png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
3207 png_pass_ystart[0]) / png_pass_yinc[0];
3208 else
3209 png_ptr->num_rows = png_ptr->height;
3210
3211 png_ptr->iwidth = (png_ptr->width +
3212 png_pass_inc[png_ptr->pass] - 1 -
3213 png_pass_start[png_ptr->pass]) /
3214 png_pass_inc[png_ptr->pass];
The Android Open Source Project893912b2009-03-03 19:30:05 -08003215 }
3216 else
3217#endif /* PNG_READ_INTERLACING_SUPPORTED */
3218 {
3219 png_ptr->num_rows = png_ptr->height;
3220 png_ptr->iwidth = png_ptr->width;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003221 }
3222 max_pixel_depth = png_ptr->pixel_depth;
3223
Patrick Scott5f6bd842010-06-28 16:55:16 -04003224#ifdef PNG_READ_PACK_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003225 if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
3226 max_pixel_depth = 8;
3227#endif
3228
Patrick Scott5f6bd842010-06-28 16:55:16 -04003229#ifdef PNG_READ_EXPAND_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003230 if (png_ptr->transformations & PNG_EXPAND)
3231 {
3232 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3233 {
3234 if (png_ptr->num_trans)
3235 max_pixel_depth = 32;
3236 else
3237 max_pixel_depth = 24;
3238 }
3239 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3240 {
3241 if (max_pixel_depth < 8)
3242 max_pixel_depth = 8;
3243 if (png_ptr->num_trans)
3244 max_pixel_depth *= 2;
3245 }
3246 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3247 {
3248 if (png_ptr->num_trans)
3249 {
3250 max_pixel_depth *= 4;
3251 max_pixel_depth /= 3;
3252 }
3253 }
3254 }
3255#endif
3256
Patrick Scott5f6bd842010-06-28 16:55:16 -04003257#ifdef PNG_READ_FILLER_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003258 if (png_ptr->transformations & (PNG_FILLER))
3259 {
3260 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
3261 max_pixel_depth = 32;
3262 else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
3263 {
3264 if (max_pixel_depth <= 8)
3265 max_pixel_depth = 16;
3266 else
3267 max_pixel_depth = 32;
3268 }
3269 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
3270 {
3271 if (max_pixel_depth <= 32)
3272 max_pixel_depth = 32;
3273 else
3274 max_pixel_depth = 64;
3275 }
3276 }
3277#endif
3278
Patrick Scott5f6bd842010-06-28 16:55:16 -04003279#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003280 if (png_ptr->transformations & PNG_GRAY_TO_RGB)
3281 {
3282 if (
Patrick Scott5f6bd842010-06-28 16:55:16 -04003283#ifdef PNG_READ_EXPAND_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003284 (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
3285#endif
Patrick Scott5f6bd842010-06-28 16:55:16 -04003286#ifdef PNG_READ_FILLER_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003287 (png_ptr->transformations & (PNG_FILLER)) ||
3288#endif
3289 png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
3290 {
3291 if (max_pixel_depth <= 16)
3292 max_pixel_depth = 32;
3293 else
3294 max_pixel_depth = 64;
3295 }
3296 else
3297 {
3298 if (max_pixel_depth <= 8)
3299 {
3300 if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3301 max_pixel_depth = 32;
3302 else
3303 max_pixel_depth = 24;
3304 }
3305 else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3306 max_pixel_depth = 64;
3307 else
3308 max_pixel_depth = 48;
3309 }
3310 }
3311#endif
3312
3313#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
3314defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003315 if (png_ptr->transformations & PNG_USER_TRANSFORM)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003316 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003317 int user_pixel_depth = png_ptr->user_transform_depth*
The Android Open Source Project893912b2009-03-03 19:30:05 -08003318 png_ptr->user_transform_channels;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003319 if (user_pixel_depth > max_pixel_depth)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003320 max_pixel_depth=user_pixel_depth;
3321 }
3322#endif
3323
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003324 /* Align the width on the next larger 8 pixels. Mainly used
3325 * for interlacing
3326 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003327 row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003328 /* Calculate the maximum bytes needed, adding a byte and a pixel
3329 * for safety's sake
3330 */
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003331 row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) +
The Android Open Source Project893912b2009-03-03 19:30:05 -08003332 1 + ((max_pixel_depth + 7) >> 3);
3333#ifdef PNG_MAX_MALLOC_64K
3334 if (row_bytes > (png_uint_32)65536L)
3335 png_error(png_ptr, "This image requires a row greater than 64KB");
3336#endif
3337
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003338 if (row_bytes + 64 > png_ptr->old_big_row_buf_size)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003339 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003340 png_free(png_ptr, png_ptr->big_row_buf);
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003341 if (png_ptr->interlaced)
Patrick Scott5f6bd842010-06-28 16:55:16 -04003342 png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
3343 row_bytes + 64);
3344 else
3345 png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
3346 row_bytes + 64);
3347 png_ptr->old_big_row_buf_size = row_bytes + 64;
3348
3349 /* Use 32 bytes of padding before and after row_buf. */
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003350 png_ptr->row_buf = png_ptr->big_row_buf + 32;
3351 png_ptr->old_big_row_buf_size = row_bytes + 64;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003352 }
3353
3354#ifdef PNG_MAX_MALLOC_64K
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003355 if ((png_uint_32)row_bytes + 1 > (png_uint_32)65536L)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003356 png_error(png_ptr, "This image requires a row greater than 64KB");
3357#endif
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003358 if ((png_uint_32)row_bytes > (png_uint_32)(PNG_SIZE_MAX - 1))
The Android Open Source Project893912b2009-03-03 19:30:05 -08003359 png_error(png_ptr, "Row has too many bytes to allocate in memory.");
3360
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003361 if (row_bytes + 1 > png_ptr->old_prev_row_size)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003362 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003363 png_free(png_ptr, png_ptr->prev_row);
3364 png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
3365 row_bytes + 1));
3366 png_memset_check(png_ptr, png_ptr->prev_row, 0, row_bytes + 1);
3367 png_ptr->old_prev_row_size = row_bytes + 1;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003368 }
3369
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003370 png_ptr->rowbytes = row_bytes;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003371
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003372 png_debug1(3, "width = %lu,", png_ptr->width);
3373 png_debug1(3, "height = %lu,", png_ptr->height);
3374 png_debug1(3, "iwidth = %lu,", png_ptr->iwidth);
3375 png_debug1(3, "num_rows = %lu,", png_ptr->num_rows);
3376 png_debug1(3, "rowbytes = %lu,", png_ptr->rowbytes);
Patrick Scott5f6bd842010-06-28 16:55:16 -04003377 png_debug1(3, "irowbytes = %lu",
3378 PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003379
3380 png_ptr->flags |= PNG_FLAG_ROW_INIT;
3381}
3382#endif /* PNG_READ_SUPPORTED */