blob: c14a782901cd81b6a9ee11e0ce1277a2e7498452 [file] [log] [blame]
Guy Schalnat0d580581995-07-20 02:43:20 -05001
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -06002/* png.c - location for general purpose libpng functions
3 *
Glenn Randers-Pehrson47457a02011-01-21 08:24:01 -06004 * Last changed in libpng 1.5.1 [(PENDING RELEASE)]
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -06005 * Copyright (c) 1998-2011 Glenn Randers-Pehrson
Glenn Randers-Pehrsond4366722000-06-04 14:29:29 -05006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
Glenn Randers-Pehrson3e61d792009-06-24 09:31:28 -05008 *
Glenn Randers-Pehrsonbfbf8652009-06-26 21:46:52 -05009 * This code is released under the libpng license.
Glenn Randers-Pehrsonc332bbc2009-06-25 13:43:50 -050010 * For conditions of distribution and use, see the disclaimer
Glenn Randers-Pehrson037023b2009-06-24 10:27:36 -050011 * and license in png.h
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -060012 */
Guy Schalnat0d580581995-07-20 02:43:20 -050013
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050014#include "pngpriv.h"
Guy Schalnat0d580581995-07-20 02:43:20 -050015
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -060016/* Generate a compiler error if there is an old png.h in the search path. */
Glenn Randers-Pehrsonaa231592011-01-22 09:41:19 -060017typedef png_libpng_version_1_5_1beta08 Your_png_h_is_not_version_1_5_1beta08;
Glenn Randers-Pehrson520a7642000-03-21 05:13:06 -060018
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060019/* Tells libpng that we have already handled the first "num_bytes" bytes
20 * of the PNG file signature. If the PNG data is embedded into another
21 * stream we can set num_bytes = 8 so that libpng will not attempt to read
22 * or write any of the magic bytes before it starts on the IHDR.
23 */
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -050024
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060025#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050026void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060027png_set_sig_bytes(png_structp png_ptr, int num_bytes)
28{
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -050029 png_debug(1, "in png_set_sig_bytes");
30
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050031 if (png_ptr == NULL)
32 return;
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -050033
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060034 if (num_bytes > 8)
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050035 png_error(png_ptr, "Too many bytes for PNG signature");
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060036
Glenn Randers-Pehrson860ab2b1999-10-14 07:43:10 -050037 png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060038}
39
40/* Checks whether the supplied bytes match the PNG signature. We allow
41 * checking less than the full 8-byte signature so that those apps that
42 * already read the first few bytes of a file to determine the file type
43 * can simply check the remaining bytes for extra assurance. Returns
44 * an integer less than, equal to, or greater than zero if sig is found,
45 * respectively, to be less than, to match, or be greater than the correct
46 * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
47 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -050048int PNGAPI
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -050049png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060050{
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -060051 png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050052
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060053 if (num_to_check > 8)
54 num_to_check = 8;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050055
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060056 else if (num_to_check < 1)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060057 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060058
Andreas Dilger47a0c421997-05-16 02:46:07 -050059 if (start > 7)
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060060 return (-1);
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060061
62 if (start + num_to_check > 8)
63 num_to_check = 8 - start;
64
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050065 return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -060066}
67
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060068#endif /* PNG_READ_SUPPORTED */
Guy Schalnat0d580581995-07-20 02:43:20 -050069
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -060070#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrsonc5080812010-10-23 08:26:26 -050071/* Function to allocate memory for zlib */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -050072PNG_FUNCTION(voidpf /* PRIVATE */,
73png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
Guy Schalnat0d580581995-07-20 02:43:20 -050074{
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050075 png_voidp ptr;
76 png_structp p=(png_structp)png_ptr;
77 png_uint_32 save_flags=p->flags;
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050078 png_alloc_size_t num_bytes;
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050079
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -050080 if (png_ptr == NULL)
81 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -050082
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050083 if (items > PNG_UINT_32_MAX/size)
84 {
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050085 png_warning (p, "Potential overflow in png_zalloc()");
86 return (NULL);
Glenn Randers-Pehrson5fea36f2004-07-28 08:20:44 -050087 }
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -050088 num_bytes = (png_alloc_size_t)items * size;
Glenn Randers-Pehrson9c0f0942002-02-21 23:14:23 -060089
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050090 p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
91 ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
92 p->flags=save_flags;
Guy Schalnat6d764711995-12-19 03:22:19 -060093
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -050094 return ((voidpf)ptr);
95}
96
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -050097/* Function to free memory for zlib */
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -050098void /* PRIVATE */
Guy Schalnat51f0eb41995-09-26 05:22:39 -050099png_zfree(voidpf png_ptr, voidpf ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500100{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600101 png_free((png_structp)png_ptr, (png_voidp)ptr);
Guy Schalnat0d580581995-07-20 02:43:20 -0500102}
103
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600104/* Reset the CRC variable to 32 bits of 1's. Care must be taken
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600105 * in case CRC is > 32 bits to leave the top bits 0.
106 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500107void /* PRIVATE */
Guy Schalnat6d764711995-12-19 03:22:19 -0600108png_reset_crc(png_structp png_ptr)
Guy Schalnat0d580581995-07-20 02:43:20 -0500109{
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600110 png_ptr->crc = crc32(0, Z_NULL, 0);
Guy Schalnat0d580581995-07-20 02:43:20 -0500111}
112
Andreas Dilger47a0c421997-05-16 02:46:07 -0500113/* Calculate the CRC over a section of data. We can only pass as
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600114 * much data to this routine as the largest single buffer size. We
115 * also check that this data will actually be used before going to the
116 * trouble of calculating it.
117 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500118void /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500119png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
Guy Schalnat0d580581995-07-20 02:43:20 -0500120{
Andreas Dilger47a0c421997-05-16 02:46:07 -0500121 int need_crc = 1;
122
123 if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
124 {
125 if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
126 (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
127 need_crc = 0;
128 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500129
Andreas Dilger47a0c421997-05-16 02:46:07 -0500130 else /* critical */
131 {
132 if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
133 need_crc = 0;
134 }
135
136 if (need_crc)
Glenn Randers-Pehrson08a33431998-03-07 06:06:55 -0600137 png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
Guy Schalnat0d580581995-07-20 02:43:20 -0500138}
Guy Schalnate5a37791996-06-05 15:50:50 -0500139
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600140/* Allocate the memory for an info_struct for the application. We don't
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600141 * really need the png_ptr, but it could potentially be useful in the
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500142 * future. This should be used in favour of malloc(png_sizeof(png_info))
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600143 * and png_info_init() so that applications that want to use a shared
144 * libpng don't have to be recompiled if png_info changes size.
145 */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -0500146PNG_FUNCTION(png_infop,PNGAPI
147png_create_info_struct,(png_structp png_ptr),PNG_ALLOCATED)
Guy Schalnate5a37791996-06-05 15:50:50 -0500148{
149 png_infop info_ptr;
150
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500151 png_debug(1, "in png_create_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500152
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500153 if (png_ptr == NULL)
154 return (NULL);
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500155
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500156#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600157 info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
158 png_ptr->malloc_fn, png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500159#else
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600160 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500161#endif
Glenn Randers-Pehrson5cded0b2001-11-07 07:10:08 -0600162 if (info_ptr != NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500163 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnate5a37791996-06-05 15:50:50 -0500164
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600165 return (info_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500166}
167
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600168/* This function frees the memory associated with a single info struct.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600169 * Normally, one would use either png_destroy_read_struct() or
170 * png_destroy_write_struct() to free an info struct, but this may be
171 * useful for some applications.
172 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500173void PNGAPI
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600174png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
175{
176 png_infop info_ptr = NULL;
177
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500178 png_debug(1, "in png_destroy_info_struct");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500179
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500180 if (png_ptr == NULL)
181 return;
182
Andreas Dilger47a0c421997-05-16 02:46:07 -0500183 if (info_ptr_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600184 info_ptr = *info_ptr_ptr;
185
Andreas Dilger47a0c421997-05-16 02:46:07 -0500186 if (info_ptr != NULL)
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600187 {
188 png_info_destroy(png_ptr, info_ptr);
189
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500190#ifdef PNG_USER_MEM_SUPPORTED
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500191 png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
192 png_ptr->mem_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500193#else
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600194 png_destroy_struct((png_voidp)info_ptr);
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500195#endif
Glenn Randers-Pehrson3f549252001-10-27 07:35:13 -0500196 *info_ptr_ptr = NULL;
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600197 }
198}
199
200/* Initialize the info structure. This is now an internal function (0.89)
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600201 * and applications using it are urged to use png_create_info_struct()
202 * instead.
203 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500204
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500205void PNGAPI
206png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
207{
208 png_infop info_ptr = *ptr_ptr;
209
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500210 png_debug(1, "in png_info_init_3");
211
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500212 if (info_ptr == NULL)
213 return;
Glenn Randers-Pehrson6b12c082006-11-14 10:53:30 -0600214
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500215 if (png_sizeof(png_info) > png_info_struct_size)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500216 {
217 png_destroy_struct(info_ptr);
218 info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
219 *ptr_ptr = info_ptr;
220 }
Glenn Randers-Pehrson8b6a8892001-05-18 04:54:50 -0500221
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500222 /* Set everything to 0 */
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500223 png_memset(info_ptr, 0, png_sizeof(png_info));
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600224}
225
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500226void PNGAPI
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500227png_data_freer(png_structp png_ptr, png_infop info_ptr,
228 int freer, png_uint_32 mask)
229{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500230 png_debug(1, "in png_data_freer");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500231
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500232 if (png_ptr == NULL || info_ptr == NULL)
233 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500234
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500235 if (freer == PNG_DESTROY_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500236 info_ptr->free_me |= mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500237
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500238 else if (freer == PNG_USER_WILL_FREE_DATA)
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500239 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500240
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500241 else
242 png_warning(png_ptr,
Glenn Randers-Pehrsonbeb572e2006-08-19 13:59:24 -0500243 "Unknown freer parameter in png_data_freer");
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500244}
245
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500246void PNGAPI
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500247png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
248 int num)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600249{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500250 png_debug(1, "in png_free_data");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500251
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600252 if (png_ptr == NULL || info_ptr == NULL)
253 return;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600254
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500255#ifdef PNG_TEXT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500256 /* Free text item num or (if num == -1) all text items */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500257 if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600258 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500259 if (num != -1)
260 {
261 if (info_ptr->text && info_ptr->text[num].key)
262 {
263 png_free(png_ptr, info_ptr->text[num].key);
264 info_ptr->text[num].key = NULL;
265 }
266 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500267
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500268 else
269 {
270 int i;
271 for (i = 0; i < info_ptr->num_text; i++)
272 png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
273 png_free(png_ptr, info_ptr->text);
274 info_ptr->text = NULL;
275 info_ptr->num_text=0;
276 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600277 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600278#endif
279
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500280#ifdef PNG_tRNS_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500281 /* Free any tRNS entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500282 if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500283 {
Glenn Randers-Pehrson6abea752009-08-08 16:52:06 -0500284 png_free(png_ptr, info_ptr->trans_alpha);
285 info_ptr->trans_alpha = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500286 info_ptr->valid &= ~PNG_INFO_tRNS;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500287 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600288#endif
289
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500290#ifdef PNG_sCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500291 /* Free any sCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500292 if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500293 {
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600294#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500295 png_free(png_ptr, info_ptr->scal_s_width);
296 png_free(png_ptr, info_ptr->scal_s_height);
297 info_ptr->scal_s_width = NULL;
298 info_ptr->scal_s_height = NULL;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600299#endif
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500300 info_ptr->valid &= ~PNG_INFO_sCAL;
301 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600302#endif
303
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500304#ifdef PNG_pCAL_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500305 /* Free any pCAL entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500306 if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500307 {
308 png_free(png_ptr, info_ptr->pcal_purpose);
309 png_free(png_ptr, info_ptr->pcal_units);
310 info_ptr->pcal_purpose = NULL;
311 info_ptr->pcal_units = NULL;
312 if (info_ptr->pcal_params != NULL)
313 {
314 int i;
315 for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
316 {
317 png_free(png_ptr, info_ptr->pcal_params[i]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600318 info_ptr->pcal_params[i] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500319 }
320 png_free(png_ptr, info_ptr->pcal_params);
321 info_ptr->pcal_params = NULL;
322 }
323 info_ptr->valid &= ~PNG_INFO_pCAL;
324 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600325#endif
326
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500327#ifdef PNG_iCCP_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500328 /* Free any iCCP entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500329 if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500330 {
331 png_free(png_ptr, info_ptr->iccp_name);
332 png_free(png_ptr, info_ptr->iccp_profile);
333 info_ptr->iccp_name = NULL;
334 info_ptr->iccp_profile = NULL;
335 info_ptr->valid &= ~PNG_INFO_iCCP;
336 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600337#endif
338
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500339#ifdef PNG_sPLT_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500340 /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500341 if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600342 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500343 if (num != -1)
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500344 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500345 if (info_ptr->splt_palettes)
346 {
347 png_free(png_ptr, info_ptr->splt_palettes[num].name);
348 png_free(png_ptr, info_ptr->splt_palettes[num].entries);
349 info_ptr->splt_palettes[num].name = NULL;
350 info_ptr->splt_palettes[num].entries = NULL;
351 }
352 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500353
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500354 else
355 {
356 if (info_ptr->splt_palettes_num)
357 {
358 int i;
359 for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
360 png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
361
362 png_free(png_ptr, info_ptr->splt_palettes);
363 info_ptr->splt_palettes = NULL;
364 info_ptr->splt_palettes_num = 0;
365 }
366 info_ptr->valid &= ~PNG_INFO_sPLT;
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500367 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600368 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600369#endif
370
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500371#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500372 if (png_ptr->unknown_chunk.data)
373 {
374 png_free(png_ptr, png_ptr->unknown_chunk.data);
375 png_ptr->unknown_chunk.data = NULL;
376 }
Glenn Randers-Pehrson895a9c92008-07-25 08:51:18 -0500377
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500378 if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600379 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500380 if (num != -1)
381 {
382 if (info_ptr->unknown_chunks)
383 {
384 png_free(png_ptr, info_ptr->unknown_chunks[num].data);
385 info_ptr->unknown_chunks[num].data = NULL;
386 }
387 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500388
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500389 else
390 {
391 int i;
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600392
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500393 if (info_ptr->unknown_chunks_num)
394 {
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -0500395 for (i = 0; i < info_ptr->unknown_chunks_num; i++)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500396 png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600397
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500398 png_free(png_ptr, info_ptr->unknown_chunks);
399 info_ptr->unknown_chunks = NULL;
400 info_ptr->unknown_chunks_num = 0;
401 }
402 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600403 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600404#endif
405
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500406#ifdef PNG_hIST_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500407 /* Free any hIST entry */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500408 if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500409 {
410 png_free(png_ptr, info_ptr->hist);
411 info_ptr->hist = NULL;
412 info_ptr->valid &= ~PNG_INFO_hIST;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500413 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600414#endif
415
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500416 /* Free any PLTE entry that was internally allocated */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500417 if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500418 {
419 png_zfree(png_ptr, info_ptr->palette);
420 info_ptr->palette = NULL;
421 info_ptr->valid &= ~PNG_INFO_PLTE;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500422 info_ptr->num_palette = 0;
423 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600424
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500425#ifdef PNG_INFO_IMAGE_SUPPORTED
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500426 /* Free any image bits attached to the info structure */
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500427 if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500428 {
429 if (info_ptr->row_pointers)
430 {
431 int row;
432 for (row = 0; row < (int)info_ptr->height; row++)
433 {
434 png_free(png_ptr, info_ptr->row_pointers[row]);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600435 info_ptr->row_pointers[row] = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500436 }
437 png_free(png_ptr, info_ptr->row_pointers);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600438 info_ptr->row_pointers = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500439 }
440 info_ptr->valid &= ~PNG_INFO_IDAT;
441 }
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600442#endif
Glenn Randers-Pehrsonfc4a1432000-05-17 17:39:34 -0500443
John Bowler56a739b2010-12-19 16:33:20 -0600444 if (num != -1)
445 mask &= ~PNG_FREE_MUL;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500446
John Bowler56a739b2010-12-19 16:33:20 -0600447 info_ptr->free_me &= ~mask;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600448}
Glenn Randers-Pehrson166c5a31999-12-10 09:43:02 -0600449
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600450/* This is an internal routine to free any memory that the info struct is
Andreas Dilger47a0c421997-05-16 02:46:07 -0500451 * pointing to before re-using it or freeing the struct itself. Recall
452 * that png_free() checks for NULL pointers for us.
453 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500454void /* PRIVATE */
Andreas Dilger02ad0ef1997-01-17 01:34:35 -0600455png_info_destroy(png_structp png_ptr, png_infop info_ptr)
456{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500457 png_debug(1, "in png_info_destroy");
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600458
459 png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
Glenn Randers-Pehrsond56aca72000-11-23 11:51:42 -0600460
Glenn Randers-Pehrsone26c0952009-09-23 11:22:08 -0500461#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600462 if (png_ptr->num_chunk_list)
463 {
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500464 png_free(png_ptr, png_ptr->chunk_list);
Glenn Randers-Pehrsonf81b50b2009-12-29 16:50:15 -0600465 png_ptr->chunk_list = NULL;
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500466 png_ptr->num_chunk_list = 0;
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600467 }
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600468#endif
Glenn Randers-Pehrsona77ef622000-02-18 13:48:52 -0600469
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500470 png_info_init_3(&info_ptr, png_sizeof(png_info));
Guy Schalnat51f0eb41995-09-26 05:22:39 -0500471}
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600472#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Guy Schalnat0d580581995-07-20 02:43:20 -0500473
Guy Schalnate5a37791996-06-05 15:50:50 -0500474/* This function returns a pointer to the io_ptr associated with the user
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600475 * functions. The application should free any memory associated with this
476 * pointer before png_write_destroy() or png_read_destroy() are called.
477 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500478png_voidp PNGAPI
Guy Schalnate5a37791996-06-05 15:50:50 -0500479png_get_io_ptr(png_structp png_ptr)
480{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500481 if (png_ptr == NULL)
482 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500483
Glenn Randers-Pehrsonb2120021998-01-31 20:07:59 -0600484 return (png_ptr->io_ptr);
Guy Schalnate5a37791996-06-05 15:50:50 -0500485}
Andreas Dilger47a0c421997-05-16 02:46:07 -0500486
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600487#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600488# ifdef PNG_STDIO_SUPPORTED
Andreas Dilger47a0c421997-05-16 02:46:07 -0500489/* Initialize the default input/output functions for the PNG file. If you
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600490 * use your own read or write routines, you can call either png_set_read_fn()
Glenn Randers-Pehrson38e6e772000-04-09 19:06:13 -0500491 * or png_set_write_fn() instead of png_init_io(). If you have defined
492 * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
493 * necessarily available.
Glenn Randers-Pehrsonb6ce43d1998-01-01 07:13:13 -0600494 */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500495void PNGAPI
Glenn Randers-Pehrson316f97a2000-07-08 13:19:41 -0500496png_init_io(png_structp png_ptr, png_FILE_p fp)
Guy Schalnate5a37791996-06-05 15:50:50 -0500497{
Glenn Randers-Pehrson51650b82008-08-05 07:44:42 -0500498 png_debug(1, "in png_init_io");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500499
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500500 if (png_ptr == NULL)
501 return;
Glenn Randers-Pehrsonb3ce3652009-08-15 21:47:03 -0500502
Guy Schalnate5a37791996-06-05 15:50:50 -0500503 png_ptr->io_ptr = (png_voidp)fp;
504}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600505# endif
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500506
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600507# ifdef PNG_TIME_RFC1123_SUPPORTED
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500508/* Convert the supplied time into an RFC 1123 string suitable for use in
509 * a "Creation Time" or other text-based time string.
510 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500511png_const_charp PNGAPI
512png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime)
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500513{
514 static PNG_CONST char short_months[12][4] =
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600515 {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
516 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500517
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500518 if (png_ptr == NULL)
519 return (NULL);
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500520
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500521 if (png_ptr->time_buffer == NULL)
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500522 {
523 png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
524 png_sizeof(char)));
525 }
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500526
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600527# ifdef USE_FAR_KEYWORD
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500528 {
529 char near_time_buf[29];
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500530 png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000",
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500531 ptime->day % 32, short_months[(ptime->month - 1) % 12],
532 ptime->year, ptime->hour % 24, ptime->minute % 60,
533 ptime->second % 61);
534 png_memcpy(png_ptr->time_buffer, near_time_buf,
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500535 29*png_sizeof(char));
Glenn Randers-Pehrson82ae3832001-04-20 10:32:10 -0500536 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600537# else
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500538 png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000",
Glenn Randers-Pehrsone1eff582001-04-14 20:15:41 -0500539 ptime->day % 32, short_months[(ptime->month - 1) % 12],
540 ptime->year, ptime->hour % 24, ptime->minute % 60,
541 ptime->second % 61);
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600542# endif
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500543 return png_ptr->time_buffer;
Glenn Randers-Pehrsonf7d1a171998-06-06 15:31:35 -0500544}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600545# endif /* PNG_TIME_RFC1123_SUPPORTED */
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600546
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600547#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600548
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500549png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600550png_get_copyright(png_const_structp png_ptr)
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600551{
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600552 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500553#ifdef PNG_STRING_COPYRIGHT
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600554 return PNG_STRING_COPYRIGHT
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500555#else
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600556# ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500557 return PNG_STRING_NEWLINE \
Glenn Randers-Pehrsonaa231592011-01-22 09:41:19 -0600558 "libpng version 1.5.1beta08 - January 22, 2011" PNG_STRING_NEWLINE \
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -0600559 "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
Glenn Randers-Pehrson43aaf6e2008-08-05 22:17:03 -0500560 "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
561 "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500562 PNG_STRING_NEWLINE;
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600563# else
Glenn Randers-Pehrsonaa231592011-01-22 09:41:19 -0600564 return "libpng version 1.5.1beta08 - January 22, 2011\
Glenn Randers-Pehrson64b863c2011-01-04 09:57:06 -0600565 Copyright (c) 1998-2011 Glenn Randers-Pehrson\
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500566 Copyright (c) 1996-1997 Andreas Dilger\
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500567 Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600568# endif
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500569#endif
Glenn Randers-Pehrson5c6aeb21998-12-29 11:47:59 -0600570}
Glenn Randers-Pehrsonbcfd15d1999-10-01 14:22:25 -0500571
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600572/* The following return the library version as a short string in the
Glenn Randers-Pehrson5b5dcf82004-07-17 22:45:44 -0500573 * format 1.0.0 through 99.99.99zz. To get the version of *.h files
574 * used with your application, print out PNG_LIBPNG_VER_STRING, which
575 * is defined in png.h.
576 * Note: now there is no difference between png_get_libpng_ver() and
577 * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
578 * it is guaranteed that png.c uses the correct version of png.h.
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600579 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500580png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600581png_get_libpng_ver(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600582{
583 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrson4c8f7262010-03-16 19:30:01 -0500584 return png_get_header_ver(png_ptr);
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600585}
586
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500587png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600588png_get_header_ver(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600589{
590 /* Version of *.h files used when building libpng */
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600591 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500592 return PNG_LIBPNG_VER_STRING;
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600593}
594
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500595png_const_charp PNGAPI
John Bowler0a5c9c02011-01-22 17:36:34 -0600596png_get_header_version(png_const_structp png_ptr)
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600597{
598 /* Returns longer string containing both version and date */
Glenn Randers-Pehrsond546f432010-12-04 20:41:36 -0600599 PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500600#ifdef __STDC__
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500601 return PNG_HEADER_VERSION_STRING
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600602# ifndef PNG_READ_SUPPORTED
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500603 " (NO READ SUPPORT)"
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600604# endif
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500605 PNG_STRING_NEWLINE;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500606#else
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500607 return PNG_HEADER_VERSION_STRING;
Glenn Randers-Pehrsone0784c72008-08-09 07:11:44 -0500608#endif
Glenn Randers-Pehrson5379b241999-11-27 10:22:33 -0600609}
610
Glenn Randers-Pehrson9c3ab682006-02-20 22:09:05 -0600611#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600612# ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
Glenn Randers-Pehrsonc1bfe682002-03-06 22:08:00 -0600613int PNGAPI
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500614png_handle_as_unknown(png_structp png_ptr, png_const_bytep chunk_name)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600615{
Glenn Randers-Pehrson4bb4d012009-05-20 12:45:29 -0500616 /* Check chunk_name and return "keep" value if it's on the list, else 0 */
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600617 int i;
618 png_bytep p;
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500619 if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600620 return 0;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500621
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500622 p = png_ptr->chunk_list + png_ptr->num_chunk_list*5 - 5;
623 for (i = png_ptr->num_chunk_list; i; i--, p -= 5)
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600624 if (!png_memcmp(chunk_name, p, 4))
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500625 return ((int)*(p + 4));
Glenn Randers-Pehrson61c32d92000-02-04 23:40:16 -0600626 return 0;
627}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600628# endif
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500629#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500630
Glenn Randers-Pehrsonf10fa3c2010-04-29 08:25:29 -0500631#ifdef PNG_READ_SUPPORTED
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500632/* This function, added to libpng-1.0.6g, is untested. */
Glenn Randers-Pehrson75294572000-05-06 14:09:57 -0500633int PNGAPI
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500634png_reset_zstream(png_structp png_ptr)
635{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500636 if (png_ptr == NULL)
637 return Z_STREAM_ERROR;
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500638
Glenn Randers-Pehrson228bd392000-04-23 23:14:02 -0500639 return (inflateReset(&png_ptr->zstream));
640}
Glenn Randers-Pehrson2b8bef12010-04-29 11:50:24 -0500641#endif /* PNG_READ_SUPPORTED */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500642
Glenn Randers-Pehrson5e5c1e12000-11-10 12:26:19 -0600643/* This function was added to libpng-1.0.7 */
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500644png_uint_32 PNGAPI
645png_access_version_number(void)
646{
647 /* Version of *.c files used when building libpng */
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -0500648 return((png_uint_32)PNG_LIBPNG_VER);
Glenn Randers-Pehrson1ef65b62000-05-12 06:19:53 -0500649}
Glenn Randers-Pehrson231e6872001-01-12 15:13:06 -0600650
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500651
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500652
653#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600654# ifdef PNG_SIZE_T
Glenn Randers-Pehrson145f5c82008-07-10 09:13:13 -0500655/* Added at libpng version 1.2.6 */
656 PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
657png_size_t PNGAPI
658png_convert_size(size_t size)
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500659{
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500660 if (size > (png_size_t)-1)
661 PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500662
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500663 return ((png_size_t)size);
Glenn Randers-Pehrson1fd5fb32001-05-06 05:34:26 -0500664}
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600665# endif /* PNG_SIZE_T */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600666
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600667/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500668# ifdef PNG_CHECK_cHRM_SUPPORTED
Glenn Randers-Pehrson glennrp@comcast.netb1c0d332009-05-15 20:39:34 -0500669
Glenn Randers-Pehrson3f705ba2009-07-23 12:53:06 -0500670int /* PRIVATE */
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600671png_check_cHRM_fixed(png_structp png_ptr,
672 png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
673 png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
674 png_fixed_point blue_x, png_fixed_point blue_y)
675{
676 int ret = 1;
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600677 unsigned long xy_hi,xy_lo,yx_hi,yx_lo;
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600678
679 png_debug(1, "in function png_check_cHRM_fixed");
Glenn Randers-Pehrsonda009802009-08-15 13:25:47 -0500680
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600681 if (png_ptr == NULL)
682 return 0;
683
Glenn Randers-Pehrson02a5e332008-11-24 22:10:23 -0600684 if (white_x < 0 || white_y <= 0 ||
685 red_x < 0 || red_y < 0 ||
686 green_x < 0 || green_y < 0 ||
687 blue_x < 0 || blue_y < 0)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600688 {
689 png_warning(png_ptr,
690 "Ignoring attempt to set negative chromaticity value");
691 ret = 0;
692 }
Glenn Randers-Pehrsond2332872010-10-12 19:19:28 -0500693 if (white_x > (png_fixed_point)PNG_UINT_31_MAX ||
694 white_y > (png_fixed_point)PNG_UINT_31_MAX ||
695 red_x > (png_fixed_point)PNG_UINT_31_MAX ||
696 red_y > (png_fixed_point)PNG_UINT_31_MAX ||
697 green_x > (png_fixed_point)PNG_UINT_31_MAX ||
698 green_y > (png_fixed_point)PNG_UINT_31_MAX ||
699 blue_x > (png_fixed_point)PNG_UINT_31_MAX ||
700 blue_y > (png_fixed_point)PNG_UINT_31_MAX )
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600701 {
702 png_warning(png_ptr,
703 "Ignoring attempt to set chromaticity value exceeding 21474.83");
704 ret = 0;
705 }
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600706 if (white_x > 100000L - white_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600707 {
708 png_warning(png_ptr, "Invalid cHRM white point");
709 ret = 0;
710 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500711
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600712 if (red_x > 100000L - red_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600713 {
714 png_warning(png_ptr, "Invalid cHRM red point");
715 ret = 0;
716 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500717
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600718 if (green_x > 100000L - green_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600719 {
720 png_warning(png_ptr, "Invalid cHRM green point");
721 ret = 0;
722 }
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500723
Glenn Randers-Pehrson71a3c1f2008-11-26 12:00:38 -0600724 if (blue_x > 100000L - blue_y)
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600725 {
726 png_warning(png_ptr, "Invalid cHRM blue point");
727 ret = 0;
728 }
Glenn Randers-Pehrsond0c40592008-11-22 07:09:51 -0600729
730 png_64bit_product(green_x - red_x, blue_y - red_y, &xy_hi, &xy_lo);
731 png_64bit_product(green_y - red_y, blue_x - red_x, &yx_hi, &yx_lo);
732
733 if (xy_hi == yx_hi && xy_lo == yx_lo)
734 {
735 png_warning(png_ptr,
736 "Ignoring attempt to set cHRM RGB triangle with zero area");
737 ret = 0;
738 }
739
Glenn Randers-Pehrsonf7831012008-11-13 06:05:13 -0600740 return ret;
741}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500742# endif /* PNG_CHECK_cHRM_SUPPORTED */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500743
744void /* PRIVATE */
745png_check_IHDR(png_structp png_ptr,
746 png_uint_32 width, png_uint_32 height, int bit_depth,
747 int color_type, int interlace_type, int compression_type,
748 int filter_type)
749{
750 int error = 0;
751
752 /* Check for width and height valid values */
753 if (width == 0)
754 {
755 png_warning(png_ptr, "Image width is zero in IHDR");
756 error = 1;
757 }
758
759 if (height == 0)
760 {
761 png_warning(png_ptr, "Image height is zero in IHDR");
762 error = 1;
763 }
764
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600765# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500766 if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrsonf24daf22010-05-06 09:44:04 -0500767
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600768# else
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500769 if (width > PNG_USER_WIDTH_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600770# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500771 {
772 png_warning(png_ptr, "Image width exceeds user limit in IHDR");
773 error = 1;
774 }
775
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600776# ifdef PNG_SET_USER_LIMITS_SUPPORTED
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500777 if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600778# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500779 if (height > PNG_USER_HEIGHT_MAX)
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600780# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500781 {
782 png_warning(png_ptr, "Image height exceeds user limit in IHDR");
783 error = 1;
784 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500785
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500786 if (width > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500787 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500788 png_warning(png_ptr, "Invalid image width in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500789 error = 1;
790 }
791
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500792 if (height > PNG_UINT_31_MAX)
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500793 {
Glenn Randers-Pehrsondd66f3e2009-09-30 14:58:28 -0500794 png_warning(png_ptr, "Invalid image height in IHDR");
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500795 error = 1;
796 }
797
Glenn Randers-Pehrsonbc363ec2010-10-12 21:17:00 -0500798 if (width > (PNG_UINT_32_MAX
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500799 >> 3) /* 8-byte RGBA pixels */
Glenn Randers-Pehrsonc5080812010-10-23 08:26:26 -0500800 - 48 /* bigrowbuf hack */
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500801 - 1 /* filter byte */
802 - 7*8 /* rounding of width to multiple of 8 pixels */
803 - 8) /* extra max_pixel_depth pad */
804 png_warning(png_ptr, "Width is too large for libpng to process pixels");
805
806 /* Check other values */
807 if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
808 bit_depth != 8 && bit_depth != 16)
809 {
810 png_warning(png_ptr, "Invalid bit depth in IHDR");
811 error = 1;
812 }
813
814 if (color_type < 0 || color_type == 1 ||
815 color_type == 5 || color_type > 6)
816 {
817 png_warning(png_ptr, "Invalid color type in IHDR");
818 error = 1;
819 }
820
821 if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
822 ((color_type == PNG_COLOR_TYPE_RGB ||
823 color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
824 color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
825 {
826 png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
827 error = 1;
828 }
829
830 if (interlace_type >= PNG_INTERLACE_LAST)
831 {
832 png_warning(png_ptr, "Unknown interlace method in IHDR");
833 error = 1;
834 }
835
836 if (compression_type != PNG_COMPRESSION_TYPE_BASE)
837 {
838 png_warning(png_ptr, "Unknown compression method in IHDR");
839 error = 1;
840 }
841
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600842# ifdef PNG_MNG_FEATURES_SUPPORTED
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500843 /* Accept filter_method 64 (intrapixel differencing) only if
844 * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
845 * 2. Libpng did not read a PNG signature (this filter_method is only
846 * used in PNG datastreams that are embedded in MNG datastreams) and
847 * 3. The application called png_permit_mng_features with a mask that
848 * included PNG_FLAG_MNG_FILTER_64 and
849 * 4. The filter_method is 64 and
850 * 5. The color_type is RGB or RGBA
851 */
852 if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) &&
853 png_ptr->mng_features_permitted)
854 png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
855
856 if (filter_type != PNG_FILTER_TYPE_BASE)
857 {
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500858 if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500859 (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
860 ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
861 (color_type == PNG_COLOR_TYPE_RGB ||
862 color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500863 {
864 png_warning(png_ptr, "Unknown filter method in IHDR");
865 error = 1;
866 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500867
Glenn Randers-Pehrson7ec330d2009-09-25 11:45:42 -0500868 if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE)
869 {
870 png_warning(png_ptr, "Invalid filter method in IHDR");
871 error = 1;
872 }
873 }
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500874
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600875# else
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500876 if (filter_type != PNG_FILTER_TYPE_BASE)
877 {
878 png_warning(png_ptr, "Unknown filter method in IHDR");
879 error = 1;
880 }
Glenn Randers-Pehrson6f6a91a2010-03-06 13:54:59 -0600881# endif
Glenn Randers-Pehrson134bbe42009-09-24 18:10:49 -0500882
883 if (error == 1)
884 png_error(png_ptr, "Invalid IHDR data");
885}
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500886
887#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
888/* ASCII to fp functions */
889/* Check an ASCII formated floating point value, see the more detailed
890 * comments in pngpriv.h
891 */
892/* The following is used internally to preserve the 'valid' flag */
893#define png_fp_add(state, flags) ((state) |= (flags))
894#define png_fp_set(state, value)\
895 ((state) = (value) | ((state) & PNG_FP_WAS_VALID))
896
897/* Internal type codes: bits above the base state! */
898#define PNG_FP_SIGN 0 /* [+-] */
899#define PNG_FP_DOT 4 /* . */
900#define PNG_FP_DIGIT 8 /* [0123456789] */
901#define PNG_FP_E 12 /* [Ee] */
902
903int /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -0500904png_check_fp_number(png_const_charp string, png_size_t size, int *statep,
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500905 png_size_tp whereami)
906{
907 int state = *statep;
908 png_size_t i = *whereami;
909
910 while (i < size)
911 {
912 int type;
913 /* First find the type of the next character */
914 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500915 char ch = string[i];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500916
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500917 if (ch >= 48 && ch <= 57)
918 type = PNG_FP_DIGIT;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500919
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500920 else switch (ch)
921 {
922 case 43: case 45: type = PNG_FP_SIGN; break;
923 case 46: type = PNG_FP_DOT; break;
924 case 69: case 101: type = PNG_FP_E; break;
925 default: goto PNG_FP_End;
926 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500927 }
928
929 /* Now deal with this type according to the current
930 * state, the type is arranged to not overlap the
931 * bits of the PNG_FP_STATE.
932 */
933 switch ((state & PNG_FP_STATE) + type)
934 {
935 case PNG_FP_INTEGER + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500936 if (state & PNG_FP_SAW_ANY)
937 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500938
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500939 png_fp_add(state, PNG_FP_SAW_SIGN);
940 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500941
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500942 case PNG_FP_INTEGER + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500943 /* Ok as trailer, ok as lead of fraction. */
944 if (state & PNG_FP_SAW_DOT) /* two dots */
945 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500946
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500947 else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */
948 png_fp_add(state, PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500949
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500950 else
951 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500952
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500953 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500954
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500955 case PNG_FP_INTEGER + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500956 if (state & PNG_FP_SAW_DOT) /* delayed fraction */
957 png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500958
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500959 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500960
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500961 break;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500962 case PNG_FP_INTEGER + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500963 if ((state & PNG_FP_SAW_DIGIT) == 0)
964 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500965
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500966 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500967
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500968 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500969
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500970 /* case PNG_FP_FRACTION + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500971 goto PNG_FP_End; ** no sign in exponent */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500972
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500973 /* case PNG_FP_FRACTION + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500974 goto PNG_FP_End; ** Because SAW_DOT is always set */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500975
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500976 case PNG_FP_FRACTION + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500977 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
978 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500979
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500980 case PNG_FP_FRACTION + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500981 /* This is correct because the trailing '.' on an
982 * integer is handled above - so we can only get here
983 * with the sequence ".E" (with no preceding digits).
984 */
985 if ((state & PNG_FP_SAW_DIGIT) == 0)
986 goto PNG_FP_End;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500987
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500988 png_fp_set(state, PNG_FP_EXPONENT);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500989
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500990 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500991
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -0500992 case PNG_FP_EXPONENT + PNG_FP_SIGN:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500993 if (state & PNG_FP_SAW_ANY)
994 goto PNG_FP_End; /* not a part of the number */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500995
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500996 png_fp_add(state, PNG_FP_SAW_SIGN);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500997
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -0500998 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -0500999
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001000 /* case PNG_FP_EXPONENT + PNG_FP_DOT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001001 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001002
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001003 case PNG_FP_EXPONENT + PNG_FP_DIGIT:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001004 png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001005
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001006 break;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001007
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001008 /* case PNG_FP_EXPONEXT + PNG_FP_E:
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001009 goto PNG_FP_End; */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001010
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001011 default: goto PNG_FP_End; /* I.e. break 2 */
1012 }
1013
1014 /* The character seems ok, continue. */
1015 ++i;
1016 }
1017
1018PNG_FP_End:
1019 /* Here at the end, update the state and return the correct
1020 * return code.
1021 */
1022 *statep = state;
1023 *whereami = i;
1024
1025 return (state & PNG_FP_SAW_DIGIT) != 0;
1026}
1027
1028
1029/* The same but for a complete string. */
1030int
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001031png_check_fp_string(png_const_charp string, png_size_t size)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001032{
1033 int state=0;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001034 png_size_t char_index=0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001035
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001036 return png_check_fp_number(string, size, &state, &char_index) &&
1037 (char_index == size || string[char_index] == 0);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001038}
1039#endif /* pCAL or sCAL */
1040
1041#ifdef PNG_READ_sCAL_SUPPORTED
1042# ifdef PNG_FLOATING_POINT_SUPPORTED
1043/* Utility used below - a simple accurate power of ten from an integral
1044 * exponent.
1045 */
1046static double
1047png_pow10(int power)
1048{
1049 int recip = 0;
1050 double d = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001051
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001052 /* Handle negative exponent with a reciprocal at the end because
1053 * 10 is exact whereas .1 is inexact in base 2
1054 */
1055 if (power < 0)
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001056 {
1057 if (power < DBL_MIN_10_EXP) return 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001058 recip = 1, power = -power;
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001059 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001060
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001061 if (power > 0)
1062 {
1063 /* Decompose power bitwise. */
1064 double mult = 10;
1065 do
1066 {
1067 if (power & 1) d *= mult;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001068 mult *= mult;
1069 power >>= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001070 }
1071 while (power > 0);
1072
1073 if (recip) d = 1/d;
1074 }
1075 /* else power is 0 and d is 1 */
1076
1077 return d;
1078}
1079
1080/* Function to format a floating point value in ASCII with a given
1081 * precision.
1082 */
1083void /* PRIVATE */
1084png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001085 double fp, unsigned int precision)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001086{
1087 /* We use standard functions from math.h, but not printf because
1088 * that would require stdio. The caller must supply a buffer of
1089 * sufficient size or we will png_error. The tests on size and
1090 * the space in ascii[] consumed are indicated below.
1091 */
1092 if (precision < 1)
1093 precision = DBL_DIG;
1094
1095 /* Enforce the limit of the implementation precision too. */
1096 if (precision > DBL_DIG+1)
1097 precision = DBL_DIG+1;
1098
1099 /* Basic sanity checks */
1100 if (size >= precision+5) /* See the requirements below. */
1101 {
1102 if (fp < 0)
1103 {
1104 fp = -fp;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001105 *ascii++ = 45; /* '-' PLUS 1 TOTAL 1*/
1106 --size;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001107 }
1108
1109 if (fp >= DBL_MIN && fp <= DBL_MAX)
1110 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001111 int exp_b10; /* A base 10 exponent */
1112 double base; /* 10^exp_b10 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001113
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001114 /* First extract a base 10 exponent of the number,
1115 * the calculation below rounds down when converting
1116 * from base 2 to base 10 (multiply by log10(2) -
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001117 * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001118 * be increased. Note that the arithmetic shift
1119 * performs a floor() unlike C arithmetic - using a
1120 * C multiply would break the following for negative
1121 * exponents.
1122 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001123 (void)frexp(fp, &exp_b10); /* exponent to base 2 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001124
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001125 exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001126
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001127 /* Avoid underflow here. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001128 base = png_pow10(exp_b10); /* May underflow */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001129
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001130 while (base < DBL_MIN || base < fp)
1131 {
1132 /* And this may overflow. */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001133 double test = png_pow10(exp_b10+1);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001134
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001135 if (test <= DBL_MAX)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001136 ++exp_b10, base = test;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001137
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001138 else
1139 break;
1140 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001141
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001142 /* Normalize fp and correct exp_b10, after this fp is in the
1143 * range [.1,1) and exp_b10 is both the exponent and the digit
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001144 * *before* which the decimal point should be inserted
1145 * (starting with 0 for the first digit). Note that this
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001146 * works even if 10^exp_b10 is out of range because of the
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001147 * test on DBL_MAX above.
1148 */
1149 fp /= base;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001150 while (fp >= 1) fp /= 10, ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001151
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001152 /* Because of the code above fp may, at this point, be
1153 * less than .1, this is ok because the code below can
1154 * handle the leading zeros this generates, so no attempt
1155 * is made to correct that here.
1156 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001157
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001158 {
1159 int czero, clead, cdigits;
1160 char exponent[10];
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001161
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001162 /* Allow up to two leading zeros - this will not lengthen
1163 * the number compared to using E-n.
1164 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001165 if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001166 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001167 czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */
1168 exp_b10 = 0; /* Dot added below before first output. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001169 }
1170 else
1171 czero = 0; /* No zeros to add */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001172
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001173 /* Generate the digit list, stripping trailing zeros and
1174 * inserting a '.' before a digit if the exponent is 0.
1175 */
1176 clead = czero; /* Count of leading zeros */
1177 cdigits = 0; /* Count of digits in list. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001178
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001179 do
1180 {
1181 double d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001182
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001183 fp *= 10;
1184 /* Use modf here, not floor and subtract, so that
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001185 * the separation is done in one step. At the end
1186 * of the loop don't break the number into parts so
1187 * that the final digit is rounded.
1188 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001189 if (cdigits+czero-clead+1 < (int)precision)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001190 fp = modf(fp, &d);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001191
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001192 else
1193 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001194 d = floor(fp + .5);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001195
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001196 if (d > 9)
1197 {
1198 /* Rounding up to 10, handle that here. */
1199 if (czero > 0)
1200 {
1201 --czero, d = 1;
1202 if (cdigits == 0) --clead;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001203 }
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001204 else
1205 {
1206 while (cdigits > 0 && d > 9)
1207 {
1208 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001209
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001210 if (exp_b10 != (-1))
1211 ++exp_b10;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001212
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001213 else if (ch == 46)
1214 {
1215 ch = *--ascii, ++size;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001216 /* Advance exp_b10 to '1', so that the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001217 * decimal point happens after the
1218 * previous digit.
1219 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001220 exp_b10 = 1;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001221 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001222
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001223 --cdigits;
1224 d = ch - 47; /* I.e. 1+(ch-48) */
1225 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001226
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001227 /* Did we reach the beginning? If so adjust the
1228 * exponent but take into account the leading
1229 * decimal point.
1230 */
1231 if (d > 9) /* cdigits == 0 */
1232 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001233 if (exp_b10 == (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001234 {
1235 /* Leading decimal point (plus zeros?), if
1236 * we lose the decimal point here it must
1237 * be reentered below.
1238 */
1239 int ch = *--ascii;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001240
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001241 if (ch == 46)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001242 ++size, exp_b10 = 1;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001243
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001244 /* Else lost a leading zero, so 'exp_b10' is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001245 * still ok at (-1)
1246 */
1247 }
1248 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001249 ++exp_b10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001250
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001251 /* In all cases we output a '1' */
1252 d = 1;
1253 }
1254 }
1255 }
1256 fp = 0; /* Guarantees termination below. */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001257 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001258
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001259 if (d == 0)
1260 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001261 ++czero;
1262 if (cdigits == 0) ++clead;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001263 }
1264 else
1265 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001266 /* Included embedded zeros in the digit count. */
1267 cdigits += czero - clead;
1268 clead = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001269
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001270 while (czero > 0)
1271 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001272 /* exp_b10 == (-1) means we just output the decimal
1273 * place - after the DP don't adjust 'exp_b10' any
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001274 * more!
1275 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001276 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001277 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001278 if (exp_b10 == 0) *ascii++ = 46, --size;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001279 /* PLUS 1: TOTAL 4 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001280 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001281 }
1282 *ascii++ = 48, --czero;
1283 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001284
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001285 if (exp_b10 != (-1))
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001286 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001287 if (exp_b10 == 0) *ascii++ = 46, --size; /* counted
1288 above */
1289 --exp_b10;
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001290 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001291 *ascii++ = (char)(48 + (int)d), ++cdigits;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001292 }
1293 }
1294 while (cdigits+czero-clead < (int)precision && fp > DBL_MIN);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001295
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001296 /* The total output count (max) is now 4+precision */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001297
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001298 /* Check for an exponent, if we don't need one we are
1299 * done and just need to terminate the string. At
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001300 * this point exp_b10==(-1) is effectively if flag - it got
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001301 * to '-1' because of the decrement after outputing
1302 * the decimal point above (the exponent required is
1303 * *not* -1!)
1304 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001305 if (exp_b10 >= (-1) && exp_b10 <= 2)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001306 {
1307 /* The following only happens if we didn't output the
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001308 * leading zeros above for negative exponent, so this
1309 * doest add to the digit requirement. Note that the
1310 * two zeros here can only be output if the two leading
1311 * zeros were *not* output, so this doesn't increase
1312 * the output count.
1313 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001314 while (--exp_b10 >= 0) *ascii++ = 48;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001315
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001316 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001317
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001318 /* Total buffer requirement (including the '\0') is
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001319 * 5+precision - see check at the start.
1320 */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001321 return;
1322 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001323
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001324 /* Here if an exponent is required, adjust size for
1325 * the digits we output but did not count. The total
1326 * digit output here so far is at most 1+precision - no
1327 * decimal point and no leading or trailing zeros have
1328 * been output.
1329 */
1330 size -= cdigits;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001331
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001332 *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision*/
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001333 if (exp_b10 < 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001334 {
1335 *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001336 exp_b10 = -exp_b10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001337 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001338
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001339 cdigits = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001340
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001341 while (exp_b10 > 0)
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001342 {
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001343 exponent[cdigits++] = (char)(48 + exp_b10 % 10);
1344 exp_b10 /= 10;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001345 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001346
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001347 /* Need another size check here for the exponent digits, so
1348 * this need not be considered above.
1349 */
1350 if ((int)size > cdigits)
1351 {
1352 while (cdigits > 0) *ascii++ = exponent[--cdigits];
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001353
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001354 *ascii = 0;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001355
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001356 return;
1357 }
1358 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001359 }
1360 else if (!(fp >= DBL_MIN))
1361 {
1362 *ascii++ = 48; /* '0' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001363 *ascii = 0;
1364 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001365 }
1366 else
1367 {
1368 *ascii++ = 105; /* 'i' */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001369 *ascii++ = 110; /* 'n' */
1370 *ascii++ = 102; /* 'f' */
1371 *ascii = 0;
1372 return;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001373 }
1374 }
1375
1376 /* Here on buffer too small. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001377 png_error(png_ptr, "ASCII conversion buffer too small");
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001378}
1379
1380# endif /* FLOATING_POINT */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001381
1382# ifdef PNG_FIXED_POINT_SUPPORTED
1383/* Function to format a fixed point value in ASCII.
1384 */
1385void /* PRIVATE */
1386png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size,
1387 png_fixed_point fp)
1388{
1389 /* Require space for 10 decimal digits, a decimal point, a minus sign and a
1390 * trailing \0, 13 characters:
1391 */
1392 if (size > 12)
1393 {
1394 png_uint_32 num;
1395
1396 /* Avoid overflow here on the minimum integer. */
1397 if (fp < 0)
1398 *ascii++ = 45, --size, num = -fp;
1399 else
1400 num = fp;
1401
1402 if (num <= 0x80000000U) /* else overflowed */
1403 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001404 unsigned int ndigits = 0, first = 16/*flag value*/;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001405 char digits[10];
1406
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001407 while (num)
1408 {
1409 /* Split the low digit off num: */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001410 unsigned int tmp = num/10;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001411 num -= tmp*10;
1412 digits[ndigits++] = (char)(48 + num);
1413 /* Record the first non-zero digit, note that this is a number
1414 * starting at 1, it's not actually the array index.
1415 */
1416 if (first == 16 && num > 0)
1417 first = ndigits;
1418 num = tmp;
1419 }
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001420
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001421 if (ndigits > 0)
1422 {
1423 while (ndigits > 5) *ascii++ = digits[--ndigits];
1424 /* The remaining digits are fractional digits, ndigits is '5' or
1425 * smaller at this point. It is certainly not zero. Check for a
1426 * non-zero fractional digit:
1427 */
1428 if (first <= 5)
1429 {
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001430 unsigned int i;
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001431 *ascii++ = 46; /* decimal point */
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001432 /* ndigits may be <5 for small numbers, output leading zeros
1433 * then ndigits digits to first:
1434 */
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001435 i = 5;
1436 while (ndigits < i) *ascii++ = 48, --i;
1437 while (ndigits >= first) *ascii++ = digits[--ndigits];
1438 /* Don't output the trailing zeros! */
1439 }
1440 }
1441 else
1442 *ascii++ = 48;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001443
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05001444 /* And null terminate the string: */
1445 *ascii = 0;
1446 return;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001447 }
1448 }
1449
1450 /* Here on buffer too small. */
1451 png_error(png_ptr, "ASCII conversion buffer too small");
1452}
1453# endif /* FIXED_POINT */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001454#endif /* READ_SCAL */
1455
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001456#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001457 !defined(PNG_FIXED_POINT_MACRO_SUPPORTED)
1458png_fixed_point
1459png_fixed(png_structp png_ptr, double fp, png_const_charp text)
1460{
1461 double r = floor(100000 * fp + .5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001462
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001463 if (r > 2147483647. || r < -2147483648.)
1464 png_fixed_error(png_ptr, text);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001465
Glenn Randers-Pehrson77c3bf12011-01-20 15:56:31 -06001466 return (png_fixed_point)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001467}
1468#endif
1469
Glenn Randers-Pehrson77396b62010-08-02 08:00:10 -05001470#if defined(PNG_READ_GAMMA_SUPPORTED) || \
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05001471 defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001472/* muldiv functions */
1473/* This API takes signed arguments and rounds the result to the nearest
1474 * integer (or, for a fixed point number - the standard argument - to
1475 * the nearest .00001). Overflow and divide by zero are signalled in
1476 * the result, a boolean - true on success, false on overflow.
1477 */
1478int
1479png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001480 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001481{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001482 /* Return a * times / divisor, rounded. */
1483 if (divisor != 0)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001484 {
1485 if (a == 0 || times == 0)
1486 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001487 *res = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001488 return 1;
1489 }
1490 else
1491 {
1492#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001493 double r = a;
1494 r *= times;
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001495 r /= divisor;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001496 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001497
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001498 /* A png_fixed_point is a 32 bit integer. */
1499 if (r <= 2147483647. && r >= -2147483648.)
1500 {
1501 *res = (png_fixed_point)r;
1502 return 1;
1503 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001504#else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001505 int negative = 0;
1506 png_uint_32 A, T, D;
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001507 png_uint_32 s16, s32, s00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001508
1509 if (a < 0)
1510 negative = 1, A = -a;
1511 else
1512 A = a;
1513
1514 if (times < 0)
1515 negative = !negative, T = -times;
1516 else
1517 T = times;
1518
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001519 if (divisor < 0)
1520 negative = !negative, D = -divisor;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001521 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001522 D = divisor;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001523
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001524 /* Following can't overflow because the arguments only
1525 * have 31 bits each, however the result may be 32 bits.
1526 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001527 s16 = (A >> 16) * (T & 0xffff) +
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001528 (A & 0xffff) * (T >> 16);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001529 /* Can't overflow because the a*times bit is only 30
1530 * bits at most.
1531 */
Glenn Randers-Pehrson3b5d6952010-08-19 08:06:12 -05001532 s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
1533 s00 = (A & 0xffff) * (T & 0xffff);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001534
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001535 s16 = (s16 & 0xffff) << 16;
1536 s00 += s16;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001537
1538 if (s00 < s16)
1539 ++s32; /* carry */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001540
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001541 if (s32 < D) /* else overflow */
1542 {
1543 /* s32.s00 is now the 64 bit product, do a standard
1544 * division, we know that s32 < D, so the maximum
1545 * required shift is 31.
1546 */
1547 int bitshift = 32;
1548 png_fixed_point result = 0; /* NOTE: signed */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001549
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001550 while (--bitshift >= 0)
1551 {
1552 png_uint_32 d32, d00;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001553
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001554 if (bitshift > 0)
1555 d32 = D >> (32-bitshift), d00 = D << bitshift;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001556
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001557 else
1558 d32 = 0, d00 = D;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001559
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001560 if (s32 > d32)
1561 {
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05001562 if (s00 < d00) --s32; /* carry */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001563 s32 -= d32, s00 -= d00, result += 1<<bitshift;
1564 }
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001565
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001566 else
1567 if (s32 == d32 && s00 >= d00)
1568 s32 = 0, s00 -= d00, result += 1<<bitshift;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001569 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001570
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001571 /* Handle the rounding. */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001572 if (s00 >= (D >> 1))
1573 ++result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001574
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001575 if (negative)
1576 result = -result;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001577
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001578 /* Check for overflow. */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001579 if ((negative && result <= 0) || (!negative && result >= 0))
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05001580 {
1581 *res = result;
1582 return 1;
1583 }
1584 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001585#endif
1586 }
1587 }
1588
1589 return 0;
1590}
1591#endif /* READ_GAMMA || INCH_CONVERSIONS */
1592
1593#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
1594/* The following is for when the caller doesn't much care about the
1595 * result.
1596 */
1597png_fixed_point
1598png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001599 png_int_32 divisor)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001600{
1601 png_fixed_point result;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001602
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06001603 if (png_muldiv(&result, a, times, divisor))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001604 return result;
1605
1606 png_warning(png_ptr, "fixed point overflow ignored");
1607 return 0;
1608}
1609#endif
1610
1611#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
1612/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
1613png_fixed_point
1614png_reciprocal(png_fixed_point a)
1615{
1616#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1617 double r = floor(1E10/a+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001618
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001619 if (r <= 2147483647. && r >= -2147483648.)
1620 return (png_fixed_point)r;
1621#else
1622 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001623
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001624 if (png_muldiv(&res, 100000, 100000, a))
1625 return res;
1626#endif
1627
1628 return 0; /* error/overflow */
1629}
1630
1631/* A local convenience routine. */
1632static png_fixed_point
1633png_product2(png_fixed_point a, png_fixed_point b)
1634{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001635 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001636#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1637 double r = a * 1E-5;
1638 r *= b;
1639 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001640
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001641 if (r <= 2147483647. && r >= -2147483648.)
1642 return (png_fixed_point)r;
1643#else
1644 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001645
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001646 if (png_muldiv(&res, a, b, 100000))
1647 return res;
1648#endif
1649
1650 return 0; /* overflow */
1651}
1652
1653/* The inverse of the above. */
1654png_fixed_point
1655png_reciprocal2(png_fixed_point a, png_fixed_point b)
1656{
Glenn Randers-Pehrson9c690912010-08-27 11:39:38 -05001657 /* The required result is 1/a * 1/b; the following preserves accuracy. */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001658#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
1659 double r = 1E15/a;
1660 r /= b;
1661 r = floor(r+.5);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001662
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001663 if (r <= 2147483647. && r >= -2147483648.)
1664 return (png_fixed_point)r;
1665#else
1666 /* This may overflow because the range of png_fixed_point isn't symmetric,
1667 * but this API is only used for the product of file and screen gamma so it
1668 * doesn't matter that the smallest number it can produce is 1/21474, not
1669 * 1/100000
1670 */
1671 png_fixed_point res = png_product2(a, b);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001672
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001673 if (res != 0)
1674 return png_reciprocal(res);
1675#endif
1676
1677 return 0; /* overflow */
1678}
1679#endif /* READ_GAMMA */
1680
1681#ifdef PNG_CHECK_cHRM_SUPPORTED
1682/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
1683 * 2010: moved from pngset.c) */
1684/*
1685 * Multiply two 32-bit numbers, V1 and V2, using 32-bit
1686 * arithmetic, to produce a 64 bit result in the HI/LO words.
1687 *
1688 * A B
1689 * x C D
1690 * ------
1691 * AD || BD
1692 * AC || CB || 0
1693 *
1694 * where A and B are the high and low 16-bit words of V1,
1695 * C and D are the 16-bit words of V2, AD is the product of
1696 * A and D, and X || Y is (X << 16) + Y.
1697*/
1698
1699void /* PRIVATE */
1700png_64bit_product (long v1, long v2, unsigned long *hi_product,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001701 unsigned long *lo_product)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001702{
1703 int a, b, c, d;
1704 long lo, hi, x, y;
1705
1706 a = (v1 >> 16) & 0xffff;
1707 b = v1 & 0xffff;
1708 c = (v2 >> 16) & 0xffff;
1709 d = v2 & 0xffff;
1710
1711 lo = b * d; /* BD */
1712 x = a * d + c * b; /* AD + CB */
1713 y = ((lo >> 16) & 0xffff) + x;
1714
1715 lo = (lo & 0xffff) | ((y & 0xffff) << 16);
1716 hi = (y >> 16) & 0xffff;
1717
1718 hi += a * c; /* AC */
1719
1720 *hi_product = (unsigned long)hi;
1721 *lo_product = (unsigned long)lo;
1722}
1723#endif /* CHECK_cHRM */
1724
1725#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
1726#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
1727/* Fixed point gamma.
1728 *
1729 * To calculate gamma this code implements fast log() and exp() calls using only
1730 * fixed point arithmetic. This code has sufficient precision for either 8 or
1731 * 16 bit sample values.
1732 *
1733 * The tables used here were calculated using simple 'bc' programs, but C double
1734 * precision floating point arithmetic would work fine. The programs are given
1735 * at the head of each table.
1736 *
1737 * 8 bit log table
1738 * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
1739 * 255, so it's the base 2 logarithm of a normalized 8 bit floating point
1740 * mantissa. The numbers are 32 bit fractions.
1741 */
1742static png_uint_32
1743png_8bit_l2[128] =
1744{
1745# if PNG_DO_BC
1746 for (i=128;i<256;++i) { .5 - l(i/255)/l(2)*65536*65536; }
1747# endif
1748 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
1749 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
1750 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
1751 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
1752 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
1753 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
1754 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
1755 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
1756 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
1757 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
1758 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
1759 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
1760 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
1761 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
1762 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
1763 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
1764 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
1765 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
1766 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
1767 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
1768 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
1769 24347096U, 0U
1770#if 0
1771 /* The following are the values for 16 bit tables - these work fine for the 8
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001772 * bit conversions but produce very slightly larger errors in the 16 bit log
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001773 * (about 1.2 as opposed to 0.7 absolute error in the final value). To use
1774 * these all the shifts below must be adjusted appropriately.
1775 */
1776 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
1777 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
1778 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
1779 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
1780 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
1781 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
1782 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
1783 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
1784 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
1785 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
1786 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
1787 1119, 744, 372
1788#endif
1789};
1790
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001791static png_int_32
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05001792png_log8bit(unsigned int x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001793{
John Bowler168a4332011-01-16 19:32:22 -06001794 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001795 /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
1796 * because the log is actually negate that means adding 1. The final
1797 * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
1798 * input), return 7.99998 for the overflow (log 0) case - so the result is
1799 * always at most 19 bits.
1800 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001801 if ((x &= 0xff) == 0)
Glenn Randers-Pehrsona5815562010-11-20 21:48:29 -06001802 return 0xffffffff;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001803
1804 if ((x & 0xf0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001805 lg2 = 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001806
1807 if ((x & 0xc0) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001808 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001809
1810 if ((x & 0x80) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001811 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001812
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001813 /* result is at most 19 bits, so this cast is safe: */
John Bowler168a4332011-01-16 19:32:22 -06001814 return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001815}
1816
1817/* The above gives exact (to 16 binary places) log2 values for 8 bit images,
1818 * for 16 bit images we use the most significant 8 bits of the 16 bit value to
1819 * get an approximation then multiply the approximation by a correction factor
1820 * determined by the remaining up to 8 bits. This requires an additional step
1821 * in the 16 bit case.
1822 *
1823 * We want log2(value/65535), we have log2(v'/255), where:
1824 *
1825 * value = v' * 256 + v''
1826 * = v' * f
1827 *
1828 * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
1829 * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
1830 * than 258. The final factor also needs to correct for the fact that our 8 bit
1831 * value is scaled by 255, whereas the 16 bit values must be scaled by 65535.
1832 *
1833 * This gives a final formula using a calculated value 'x' which is value/v' and
1834 * scaling by 65536 to match the above table:
1835 *
1836 * log2(x/257) * 65536
1837 *
1838 * Since these numbers are so close to '1' we can use simple linear
1839 * interpolation between the two end values 256/257 (result -368.61) and 258/257
1840 * (result 367.179). The values used below are scaled by a further 64 to give
1841 * 16 bit precision in the interpolation:
1842 *
1843 * Start (256): -23591
1844 * Zero (257): 0
1845 * End (258): 23499
1846 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001847static png_int_32
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001848png_log16bit(png_uint_32 x)
1849{
John Bowler168a4332011-01-16 19:32:22 -06001850 unsigned int lg2 = 0;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001851
1852 /* As above, but now the input has 16 bits. */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001853 if ((x &= 0xffff) == 0)
1854 return 0xffffffff;
1855
1856 if ((x & 0xff00) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001857 lg2 = 8, x <<= 8;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001858
1859 if ((x & 0xf000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001860 lg2 += 4, x <<= 4;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001861
1862 if ((x & 0xc000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001863 lg2 += 2, x <<= 2;
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001864
1865 if ((x & 0x8000) == 0)
John Bowler168a4332011-01-16 19:32:22 -06001866 lg2 += 1, x <<= 1;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001867
1868 /* Calculate the base logarithm from the top 8 bits as a 28 bit fractional
1869 * value.
1870 */
John Bowler168a4332011-01-16 19:32:22 -06001871 lg2 <<= 28;
1872 lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001873
1874 /* Now we need to interpolate the factor, this requires a division by the top
1875 * 8 bits. Do this with maximum precision.
1876 */
1877 x = ((x << 16) + (x >> 9)) / (x >> 8);
1878
1879 /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
1880 * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
1881 * 16 bits to interpolate to get the low bits of the result. Round the
1882 * answer. Note that the end point values are scaled by 64 to retain overall
John Bowler168a4332011-01-16 19:32:22 -06001883 * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001884 * the overall scaling by 6-12. Round at every step.
1885 */
1886 x -= 1U << 24;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001887
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001888 if (x <= 65536U) /* <= '257' */
John Bowler168a4332011-01-16 19:32:22 -06001889 lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001890
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001891 else
John Bowler168a4332011-01-16 19:32:22 -06001892 lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001893
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001894 /* Safe, because the result can't have more than 20 bits: */
John Bowler168a4332011-01-16 19:32:22 -06001895 return (png_int_32)((lg2 + 2048) >> 12);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001896}
1897
1898/* The 'exp()' case must invert the above, taking a 20 bit fixed point
1899 * logarithmic value and returning a 16 or 8 bit number as appropriate. In
1900 * each case only the low 16 bits are relevant - the fraction - since the
1901 * integer bits (the top 4) simply determine a shift.
1902 *
1903 * The worst case is the 16 bit distinction between 65535 and 65534, this
1904 * requires perhaps spurious accuracty in the decoding of the logarithm to
1905 * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance
1906 * of getting this accuracy in practice.
1907 *
1908 * To deal with this the following exp() function works out the exponent of the
1909 * frational part of the logarithm by using an accurate 32 bit value from the
1910 * top four fractional bits then multiplying in the remaining bits.
1911 */
1912static png_uint_32
1913png_32bit_exp[16] =
1914{
1915# if PNG_DO_BC
1916 for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; }
1917# endif
1918 /* NOTE: the first entry is deliberately set to the maximum 32 bit value. */
1919 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
1920 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
1921 2553802834U, 2445529972U, 2341847524U, 2242560872U
1922};
1923
1924/* Adjustment table; provided to explain the numbers in the code below. */
1925#if PNG_DO_BC
1926for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
1927 11 44937.64284865548751208448
1928 10 45180.98734845585101160448
1929 9 45303.31936980687359311872
1930 8 45364.65110595323018870784
1931 7 45395.35850361789624614912
1932 6 45410.72259715102037508096
1933 5 45418.40724413220722311168
1934 4 45422.25021786898173001728
1935 3 45424.17186732298419044352
1936 2 45425.13273269940811464704
1937 1 45425.61317555035558641664
1938 0 45425.85339951654943850496
1939#endif
1940
1941static png_uint_32
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001942png_exp(png_fixed_point x)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001943{
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001944 if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001945 {
1946 /* Obtain a 4 bit approximation */
1947 png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf];
1948
1949 /* Incorporate the low 12 bits - these decrease the returned value by
1950 * multiplying by a number less than 1 if the bit is set. The multiplier
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05001951 * is determined by the above table and the shift. Notice that the values
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001952 * converge on 45426 and this is used to allow linear interpolation of the
1953 * low bits.
1954 */
Glenn Randers-Pehrson233357e2010-07-29 21:49:38 -05001955 if (x & 0x800)
1956 e -= (((e >> 16) * 44938U) + 16U) >> 5;
1957
1958 if (x & 0x400)
1959 e -= (((e >> 16) * 45181U) + 32U) >> 6;
1960
1961 if (x & 0x200)
1962 e -= (((e >> 16) * 45303U) + 64U) >> 7;
1963
1964 if (x & 0x100)
1965 e -= (((e >> 16) * 45365U) + 128U) >> 8;
1966
1967 if (x & 0x080)
1968 e -= (((e >> 16) * 45395U) + 256U) >> 9;
1969
1970 if (x & 0x040)
1971 e -= (((e >> 16) * 45410U) + 512U) >> 10;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001972
1973 /* And handle the low 6 bits in a single block. */
1974 e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
1975
1976 /* Handle the upper bits of x. */
1977 e >>= x >> 16;
1978 return e;
1979 }
1980
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05001981 /* Check for overflow */
1982 if (x <= 0)
1983 return png_32bit_exp[0];
1984
1985 /* Else underflow */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001986 return 0;
1987}
1988
1989static png_byte
John Bowler168a4332011-01-16 19:32:22 -06001990png_exp8bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001991{
1992 /* Get a 32 bit value: */
John Bowler168a4332011-01-16 19:32:22 -06001993 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05001994
1995 /* Convert the 32 bit value to 0..255 by multiplying by 256-1, note that the
1996 * second, rounding, step can't overflow because of the first, subtraction,
1997 * step.
1998 */
1999 x -= x >> 8;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002000 return (png_byte)((x + 0x7fffffU) >> 24);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002001}
2002
2003static png_uint_16
John Bowler168a4332011-01-16 19:32:22 -06002004png_exp16bit(png_fixed_point lg2)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002005{
2006 /* Get a 32 bit value: */
John Bowler168a4332011-01-16 19:32:22 -06002007 png_uint_32 x = png_exp(lg2);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002008
2009 /* Convert the 32 bit value to 0..65535 by multiplying by 65536-1: */
2010 x -= x >> 16;
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002011 return (png_uint_16)((x + 32767U) >> 16);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002012}
2013#endif /* FLOATING_ARITHMETIC */
2014
2015png_byte
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002016png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002017{
2018 if (value > 0 && value < 255)
2019 {
2020# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002021 double r = floor(255*pow(value/255.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002022 return (png_byte)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002023# else
John Bowler168a4332011-01-16 19:32:22 -06002024 png_int_32 lg2 = png_log8bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002025 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002026
John Bowler168a4332011-01-16 19:32:22 -06002027 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002028 return png_exp8bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002029
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002030 /* Overflow. */
2031 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002032# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002033 }
2034
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002035 return (png_byte)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002036}
2037
2038png_uint_16
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002039png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002040{
2041 if (value > 0 && value < 65535)
2042 {
2043# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002044 double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002045 return (png_uint_16)r;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002046# else
John Bowler168a4332011-01-16 19:32:22 -06002047 png_int_32 lg2 = png_log16bit(value);
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002048 png_fixed_point res;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002049
John Bowler168a4332011-01-16 19:32:22 -06002050 if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1))
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002051 return png_exp16bit(res);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002052
Glenn Randers-Pehrson3df324d2010-07-31 13:45:04 -05002053 /* Overflow. */
2054 value = 0;
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002055# endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002056 }
2057
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002058 return (png_uint_16)value;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002059}
2060
2061/* This does the right thing based on the bit_depth field of the
2062 * png_struct, interpreting values as 8 or 16 bit. While the result
2063 * is nominally a 16 bit value if bit depth is 8 then the result is
2064 * 8 bit (as are the arguments.)
2065 */
2066png_uint_16 /* PRIVATE */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002067png_gamma_correct(png_structp png_ptr, unsigned int value,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002068 png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002069{
2070 if (png_ptr->bit_depth == 8)
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002071 return png_gamma_8bit_correct(value, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002072
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002073 else
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002074 return png_gamma_16bit_correct(value, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002075}
2076
2077/* This is the shared test on whether a gamma value is 'significant' - whether
2078 * it is worth doing gamma correction.
2079 */
2080int /* PRIVATE */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002081png_gamma_significant(png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002082{
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002083 return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
2084 gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002085}
2086
2087/* Internal function to build a single 16 bit table - the table consists of
2088 * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
2089 * to shift the input values right (or 16-number_of_signifiant_bits).
2090 *
Glenn Randers-Pehrsona774c5d2010-08-26 19:37:55 -05002091 * The caller is responsible for ensuring that the table gets cleaned up on
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002092 * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
2093 * should be somewhere that will be cleaned.
2094 */
2095static void
2096png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002097 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002098{
2099 /* Various values derived from 'shift': */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002100 PNG_CONST unsigned int num = 1U << (8U - shift);
2101 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2102 PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
2103 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002104
2105 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002106 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002107
2108 for (i = 0; i < num; i++)
2109 {
2110 png_uint_16p sub_table = table[i] =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002111 (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002112
2113 /* The 'threshold' test is repeated here because it can arise for one of
2114 * the 16 bit tables even if the others don't hit it.
2115 */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002116 if (png_gamma_significant(gamma_val))
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002117 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002118 /* The old code would overflow at the end and this would cause the
2119 * 'pow' function to return a result >1, resulting in an
2120 * arithmetic error. This code follows the spec exactly; ig is
2121 * the recovered input sample, it always has 8-16 bits.
2122 *
2123 * We want input * 65535/max, rounded, the arithmetic fits in 32
2124 * bits (unsigned) so long as max <= 32767.
2125 */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002126 unsigned int j;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002127 for (j = 0; j < 256; j++)
2128 {
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002129 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002130# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002131 /* Inline the 'max' scaling operation: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002132 double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002133 sub_table[j] = (png_uint_16)d;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002134# else
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002135 if (shift)
Glenn Randers-Pehrson4eb18e92010-07-30 14:46:52 -05002136 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002137
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002138 sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002139# endif
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002140 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002141 }
2142 else
2143 {
2144 /* We must still build a table, but do it the fast way. */
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002145 unsigned int j;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002146
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002147 for (j = 0; j < 256; j++)
2148 {
2149 png_uint_32 ig = (j << (8-shift)) + i;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002150
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002151 if (shift)
2152 ig = (ig * 65535U + max_by_2)/max;
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002153
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002154 sub_table[j] = (png_uint_16)ig;
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002155 }
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002156 }
2157 }
2158}
2159
2160/* NOTE: this function expects the *inverse* of the overall gamma transformation
2161 * required.
2162 */
2163static void
2164png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002165 PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002166{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002167 PNG_CONST unsigned int num = 1U << (8U - shift);
2168 PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
2169 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002170 png_uint_32 last;
2171
2172 png_uint_16pp table = *ptable =
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002173 (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002174
2175 /* 'num' is the number of tables and also the number of low bits of low
2176 * bits of the input 16 bit value used to select a table. Each table is
2177 * itself index by the high 8 bits of the value.
2178 */
2179 for (i = 0; i < num; i++)
2180 table[i] = (png_uint_16p)png_malloc(png_ptr,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002181 256 * png_sizeof(png_uint_16));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002182
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002183 /* 'gamma_val' is set to the reciprocal of the value calculated above, so
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002184 * pow(out,g) is an *input* value. 'last' is the last input value set.
2185 *
2186 * In the loop 'i' is used to find output values. Since the output is 8
2187 * bit there are only 256 possible values. The tables are set up to
2188 * select the closest possible output value for each input by finding
2189 * the input value at the boundary between each pair of output values
2190 * and filling the table up to that boundary with the lower output
2191 * value.
2192 *
2193 * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9 bit
2194 * values the code below uses a 16 bit value in i; the values start at
2195 * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
2196 * entries are filled with 255). Start i at 128 and fill all 'last'
2197 * table entries <= 'max'
2198 */
2199 last = 0;
2200 for (i = 0; i < 255; ++i) /* 8 bit output value */
2201 {
2202 /* Find the corresponding maximum input value */
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002203 png_uint_16 out = (png_uint_16)(i * 257U); /* 16 bit output value */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002204
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002205 /* Find the boundary value in 16 bits: */
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002206 png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002207
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002208 /* Adjust (round) to (16-shift) bits: */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002209 bound = (bound * max + 32768U)/65535U + 1U;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002210
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002211 while (last < bound)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002212 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002213 table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
2214 last++;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002215 }
2216 }
2217
2218 /* And fill in the final entries. */
2219 while (last < (num << 8))
2220 {
2221 table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
2222 last++;
2223 }
2224}
2225
2226/* Build a single 8 bit table: same as the 16 bit case but much simpler (and
2227 * typically much faster). Note that libpng currently does no sBIT processing
2228 * (apparently contrary to the spec) so a 256 entry table is always generated.
2229 */
2230static void
2231png_build_8bit_table(png_structp png_ptr, png_bytepp ptable,
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002232 PNG_CONST png_fixed_point gamma_val)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002233{
Glenn Randers-Pehrsone600c512010-08-18 07:25:46 -05002234 unsigned int i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002235 png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
2236
Glenn Randers-Pehrson2368a922011-01-16 13:32:05 -06002237 if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++)
2238 table[i] = png_gamma_8bit_correct(i, gamma_val);
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002239
Glenn Randers-Pehrson4009a762010-07-31 06:34:36 -05002240 else for (i=0; i<256; ++i)
2241 table[i] = (png_byte)i;
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002242}
2243
2244/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
2245 * tables, we don't make a full table if we are reducing to 8-bit in
2246 * the future. Note also how the gamma_16 tables are segmented so that
2247 * we don't need to allocate > 64K chunks for a full 16-bit table.
2248 */
2249void /* PRIVATE */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002250png_build_gamma_table(png_structp png_ptr, int bit_depth)
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002251{
2252 png_debug(1, "in png_build_gamma_table");
2253
2254 if (bit_depth <= 8)
2255 {
2256 png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002257 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2258 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002259
2260#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
2261 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
2262 if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
2263 {
2264 png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002265 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002266
2267 png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002268 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2269 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002270 }
2271#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
2272 }
2273 else
2274 {
2275 png_byte shift, sig_bit;
2276
2277 if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
2278 {
2279 sig_bit = png_ptr->sig_bit.red;
2280
2281 if (png_ptr->sig_bit.green > sig_bit)
2282 sig_bit = png_ptr->sig_bit.green;
2283
2284 if (png_ptr->sig_bit.blue > sig_bit)
2285 sig_bit = png_ptr->sig_bit.blue;
2286 }
2287 else
2288 sig_bit = png_ptr->sig_bit.gray;
2289
2290 /* 16 bit gamma code uses this equation:
2291 *
2292 * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
2293 *
2294 * Where 'iv' is the input color value and 'ov' is the output value -
2295 * pow(iv, gamma).
2296 *
2297 * Thus the gamma table consists of up to 256 256 entry tables. The table
2298 * is selected by the (8-gamma_shift) most significant of the low 8 bits of
2299 * the color value then indexed by the upper 8 bits:
2300 *
2301 * table[low bits][high 8 bits]
2302 *
2303 * So the table 'n' corresponds to all those 'iv' of:
2304 *
2305 * <all high 8 bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
2306 *
2307 */
Glenn Randers-Pehrson67439c42010-08-19 07:01:09 -05002308 if (sig_bit > 0 && sig_bit < 16U)
2309 shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002310
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002311 else
2312 shift = 0; /* keep all 16 bits */
2313
2314 if (png_ptr->transformations & PNG_16_TO_8)
2315 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002316 /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
2317 * the significant bits in the *input* when the output will
2318 * eventually be 8 bits. By default it is 11.
2319 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002320 if (shift < (16U - PNG_MAX_GAMMA_8))
2321 shift = (16U - PNG_MAX_GAMMA_8);
2322 }
2323
2324 if (shift > 8U)
2325 shift = 8U; /* Guarantees at least one table! */
2326
2327 png_ptr->gamma_shift = shift;
2328
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002329#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002330 if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002331#endif
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002332 png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
2333 png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma,
2334 png_ptr->screen_gamma) : PNG_FP_1);
2335
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002336#ifdef PNG_16BIT_SUPPORTED
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002337 else
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002338 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
2339 png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->gamma,
2340 png_ptr->screen_gamma) : PNG_FP_1);
Glenn Randers-Pehrson4e487612010-08-26 21:41:04 -05002341#endif
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002342
2343#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
2344 defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
2345 if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
2346 {
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002347 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002348 png_reciprocal(png_ptr->gamma));
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002349
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002350 /* Notice that the '16 from 1' table should be full precision, however
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002351 * the lookup on this table still uses gamma_shift, so it can't be.
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002352 * TODO: fix this.
2353 */
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002354 png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
Glenn Randers-Pehrson7b81e2e2010-07-29 22:54:34 -05002355 png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
2356 png_ptr->gamma/* Probably doing rgb_to_gray */);
Glenn Randers-Pehrson31aee0d2010-07-29 17:39:14 -05002357 }
2358#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
2359 }
2360}
2361#endif /* READ_GAMMA */
Glenn Randers-Pehrson29034c52010-07-29 17:58:49 -05002362#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */