1893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
2893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* png.c - location for general purpose libpng functions
3893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project *
43cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * Last changed in libpng 1.6.33 [September 28, 2017]
53cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
6893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott *
9a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott * This code is released under the libpng license.
10a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott * For conditions of distribution and use, see the disclaimer
11a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott * and license in png.h
12893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
13893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
14b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#include "pngpriv.h"
15893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
16893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Generate a compiler error if there is an old png.h in the search path. */
173cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins IIItypedef png_libpng_version_1_6_34 Your_png_h_is_not_version_1_6_34;
183cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III
193cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#ifdef __GNUC__
203cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III/* The version tests may need to be added to, but the problem warning has
213cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * consistently been fixed in GCC versions which obtain wide-spread release.
223cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * The problem is that many versions of GCC rearrange comparison expressions in
233cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * the optimizer in such a way that the results of the comparison will change
243cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * if signed integer overflow occurs.  Such comparisons are not permitted in
253cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * ANSI C90, however GCC isn't clever enough to work out that that do not occur
263cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * below in png_ascii_from_fp and png_muldiv, so it produces a warning with
273cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * -Wextra.  Unfortunately this is highly dependent on the optimizer and the
283cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * machine architecture so the warning comes and goes unpredictably and is
293cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * impossible to "fix", even were that a good idea.
303cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III */
313cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#if __GNUC__ == 7 && __GNUC_MINOR__ == 1
323cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#define GCC_STRICT_OVERFLOW 1
333cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GNU 7.1.x */
343cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GNU */
353cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#ifndef GCC_STRICT_OVERFLOW
363cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#define GCC_STRICT_OVERFLOW 0
373cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif
38893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
39893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Tells libpng that we have already handled the first "num_bytes" bytes
40893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * of the PNG file signature.  If the PNG data is embedded into another
41893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * stream we can set num_bytes = 8 so that libpng will not attempt to read
42893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * or write any of the magic bytes before it starts on the IHDR.
43893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
44893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
45893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#ifdef PNG_READ_SUPPORTED
46893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid PNGAPI
47b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_set_sig_bytes(png_structrp png_ptr, int num_bytes)
48893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   unsigned int nb = (unsigned int)num_bytes;
509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
515f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   png_debug(1, "in png_set_sig_bytes");
525f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
53a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
54a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return;
555f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (num_bytes < 0)
579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      nb = 0;
589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (nb > 8)
60b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_error(png_ptr, "Too many bytes for PNG signature");
61893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   png_ptr->sig_bytes = (png_byte)nb;
63893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
64893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
65893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Checks whether the supplied bytes match the PNG signature.  We allow
66893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * checking less than the full 8-byte signature so that those apps that
67893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * already read the first few bytes of a file to determine the file type
68893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * can simply check the remaining bytes for extra assurance.  Returns
69893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * an integer less than, equal to, or greater than zero if sig is found,
70893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * respectively, to be less than, to match, or be greater than the correct
71b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG signature (this is the same behavior as strcmp, memcmp, etc).
72893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
73893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectint PNGAPI
74b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
75893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
76893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
77b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
78893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (num_to_check > 8)
79893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      num_to_check = 8;
80b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
81893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   else if (num_to_check < 1)
82893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      return (-1);
83893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
84893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (start > 7)
85893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      return (-1);
86893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
87893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (start + num_to_check > 8)
88893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      num_to_check = 8 - start;
89893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
90b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));
91893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
92893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ */
94893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
95893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
96b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Function to allocate memory for zlib */
97b50c217251b086440efcdb273c22f86a06c80cbaChris CraikPNG_FUNCTION(voidpf /* PRIVATE */,
98b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
99893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_alloc_size_t num_bytes = size;
101893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
102a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return NULL;
104893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (items >= (~(png_alloc_size_t)0)/size)
106893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning (png_voidcast(png_structrp, png_ptr),
1087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "Potential overflow in png_zalloc()");
109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return NULL;
110893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   num_bytes *= items;
113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes);
114893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
115893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
116a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott/* Function to free memory for zlib */
1175f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scottvoid /* PRIVATE */
118893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectpng_zfree(voidpf png_ptr, voidpf ptr)
119893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_voidcast(png_const_structrp,png_ptr), ptr);
121893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
122893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
123893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Reset the CRC variable to 32 bits of 1's.  Care must be taken
124893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * in case CRC is > 32 bits to leave the top bits 0.
125893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
126893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid /* PRIVATE */
127b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_reset_crc(png_structrp png_ptr)
128893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
1299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* The cast is safe because the crc is a 32-bit value. */
130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0);
131893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
132893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
133893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Calculate the CRC over a section of data.  We can only pass as
134893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * much data to this routine as the largest single buffer size.  We
135893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * also check that this data will actually be used before going to the
136893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * trouble of calculating it.
137893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
138893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid /* PRIVATE */
139b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length)
140893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
141893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   int need_crc = 1;
142893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
1439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0)
144893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
145893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
146893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
147893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project         need_crc = 0;
148893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else /* critical */
151893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
1529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0)
153893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project         need_crc = 0;
154893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
155893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* 'uLong' is defined in zlib.h as unsigned long; this means that on some
1579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * systems it is a 64-bit value.  crc32, however, returns 32 bits so the
158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * following cast is safe.  'uInt' may be no more than 16 bits, so it is
159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * necessary to perform a loop here.
160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (need_crc != 0 && length > 0)
162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      uLong crc = png_ptr->crc; /* Should never issue a warning */
164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      do
166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         uInt safe_length = (uInt)length;
1689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifndef __COVERITY__
169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (safe_length == 0)
170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            safe_length = (uInt)-1; /* evil, but safe */
1719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         crc = crc32(crc, ptr, safe_length);
174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* The following should never issue compiler warnings; if they do the
176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * target system has characteristics that will probably violate other
177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * assumptions within the libpng code.
178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         ptr += safe_length;
180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         length -= safe_length;
181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      while (length > 0);
183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* And the following is always safe because the crc is only 32 bits. */
185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_ptr->crc = (png_uint_32)crc;
186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Check a user supplied version number, called from both read and write
190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * functions that create a png_struct.
191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
192b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint
193b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver)
194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1957a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   /* Libpng versions 1.0.0 and later are binary compatible if the version
1967a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * string matches through the second '.'; we must recompile any
1977a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * applications that use any older library version.
1987a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    */
1999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (user_png_ver != NULL)
201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      int i = -1;
2039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      int found_dots = 0;
204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      do
206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         i++;
2089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
2109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (user_png_ver[i] == '.')
2119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            found_dots++;
2129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      } while (found_dots < 2 && user_png_ver[i] != 0 &&
2139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            PNG_LIBPNG_VER_STRING[i] != 0);
214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0)
220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_WARNINGS_SUPPORTED
2229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      size_t pos = 0;
2239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      char m[128];
224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      pos = png_safecat(m, (sizeof m), pos,
2269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          "Application built with libpng-");
2279b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      pos = png_safecat(m, (sizeof m), pos, user_png_ver);
2289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      pos = png_safecat(m, (sizeof m), pos, " but running with ");
2299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
2309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      PNG_UNUSED(pos)
231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_warning(png_ptr, m);
233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_ERROR_NUMBERS_SUPPORTED
2369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_ptr->flags = 0;
237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 0;
240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Success return. */
243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
244893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
245893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Generic function to create a png_struct for either read or write - this
247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * contains the common initialization.
248893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
249b50c217251b086440efcdb273c22f86a06c80cbaChris CraikPNG_FUNCTION(png_structp /* PRIVATE */,
250b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_struct create_struct;
255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_SETJMP_SUPPORTED
256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      jmp_buf create_jmp_buf;
257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This temporary stack-allocated structure is used to provide a place to
260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * build enough context to allow the user provided memory allocator (if any)
261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * to be called.
262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   memset(&create_struct, 0, (sizeof create_struct));
264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Added at libpng-1.2.6 */
266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_USER_LIMITS_SUPPORTED
267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      create_struct.user_width_max = PNG_USER_WIDTH_MAX;
268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      create_struct.user_height_max = PNG_USER_HEIGHT_MAX;
269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_USER_CHUNK_CACHE_MAX
2719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* Added at libpng-1.2.43 and 1.4.0 */
2729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_USER_CHUNK_MALLOC_MAX
2769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists
2779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * in png_struct regardless.
2789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       */
2799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The following two API calls simply set fields in png_struct, so it is safe
284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * to do them now even though error handling is not yet set up.
285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_USER_MEM_SUPPORTED
287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn);
288b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  else
289b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      PNG_UNUSED(mem_ptr)
290b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      PNG_UNUSED(malloc_fn)
291b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      PNG_UNUSED(free_fn)
292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
293b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* (*error_fn) can return control to the caller after the error_ptr is set,
295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * this will result in a memory leak unless the error_fn does something
296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * extremely sophisticated.  The design lacks merit but is implicit in the
297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * API.
298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn);
300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_SETJMP_SUPPORTED
302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (!setjmp(create_jmp_buf))
3039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#  endif
304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#  ifdef PNG_SETJMP_SUPPORTED
306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Temporarily fake out the longjmp information until we have
307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * successfully completed this function.  This only works if we have
308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * setjmp() support compiled in, but it is safe - this stuff should
309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * never happen.
310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         create_struct.jmp_buf_ptr = &create_jmp_buf;
312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         create_struct.jmp_buf_size = 0; /*stack allocation*/
313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         create_struct.longjmp_fn = longjmp;
314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Call the general version checker (shared with read and write code):
316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
3179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (png_user_version_check(&create_struct, user_png_ver) != 0)
318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_structrp png_ptr = png_voidcast(png_structrp,
3207a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                png_malloc_warn(&create_struct, (sizeof *png_ptr)));
321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (png_ptr != NULL)
323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* png_ptr->zstream holds a back-pointer to the png_struct, so
325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * this can only be done now:
326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               create_struct.zstream.zalloc = png_zalloc;
328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               create_struct.zstream.zfree = png_zfree;
329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               create_struct.zstream.opaque = png_ptr;
330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#              ifdef PNG_SETJMP_SUPPORTED
3329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               /* Eliminate the local error handling: */
3339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               create_struct.jmp_buf_ptr = NULL;
3349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               create_struct.jmp_buf_size = 0;
3359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               create_struct.longjmp_fn = 0;
336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#              endif
337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               *png_ptr = create_struct;
339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* This is the successful return point */
341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               return png_ptr;
342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* A longjmp because of a bug in the application storage allocator or a
347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * simple failure to allocate the png_struct.
348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return NULL;
350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Allocate the memory for an info_struct for the application. */
353b50c217251b086440efcdb273c22f86a06c80cbaChris CraikPNG_FUNCTION(png_infop,PNGAPI
354b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED)
355893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_inforp info_ptr;
357893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
3584215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   png_debug(1, "in png_create_info_struct");
3595f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
360a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return NULL;
362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Use the internal API that does not (or at least should not) error out, so
364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * that this call always returns ok.  The application typically sets up the
365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * error handling *after* creating the info_struct because this is the way it
366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * has always been done in 'example.c'.
367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr,
3697a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       (sizeof *info_ptr)));
3705f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
371893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (info_ptr != NULL)
372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      memset(info_ptr, 0, (sizeof *info_ptr));
373893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return info_ptr;
375893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
376893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
377893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* This function frees the memory associated with a single info struct.
378893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * Normally, one would use either png_destroy_read_struct() or
379893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * png_destroy_write_struct() to free an info struct, but this may be
380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * useful for some applications.  From libpng 1.6.0 this function is also used
381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * internally to implement the png_info release part of the 'struct' destroy
382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * APIs.  This ensures that all possible approaches free the same data (all of
383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * it).
384893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
385893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid PNGAPI
386b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr)
387893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_inforp info_ptr = NULL;
3895f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
3905f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   png_debug(1, "in png_destroy_info_struct");
3915f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
392a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
393a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return;
394893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
395893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (info_ptr_ptr != NULL)
396893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      info_ptr = *info_ptr_ptr;
397893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
398893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (info_ptr != NULL)
399893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Do this first in case of an error below; if the app implements its own
401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * memory management this can lead to png_free calling png_error, which
402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * will abort this routine and return control to the app error handler.
403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * An infinite loop may result if it then tries to free the same info
404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * ptr.
405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
406893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      *info_ptr_ptr = NULL;
407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      memset(info_ptr, 0, (sizeof *info_ptr));
410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_free(png_ptr, info_ptr);
411893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
412893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
413893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
414893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Initialize the info structure.  This is now an internal function (0.89)
415893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * and applications using it are urged to use png_create_info_struct()
416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * instead.  Use deprecated in 1.6.0, internal use removed (used internally it
417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is just a memset).
418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * NOTE: it is almost inconceivable that this API is used because it bypasses
420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the user-memory mechanism and the user error handling/warning mechanisms in
421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * those cases where it does anything other than a memset.
422893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
423b50c217251b086440efcdb273c22f86a06c80cbaChris CraikPNG_FUNCTION(void,PNGAPI
424b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size),
4257a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    PNG_DEPRECATED)
426893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_inforp info_ptr = *ptr_ptr;
428893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
4295f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   png_debug(1, "in png_info_init_3");
4305f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
431a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (info_ptr == NULL)
432a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return;
433893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((sizeof (png_info)) > png_info_struct_size)
435a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      *ptr_ptr = NULL;
437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The following line is why this API should not be used: */
438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      free(info_ptr);
439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL,
4407a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          (sizeof *info_ptr)));
4419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (info_ptr == NULL)
4429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return;
443a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      *ptr_ptr = info_ptr;
444a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
445893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
446a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Set everything to 0 */
447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   memset(info_ptr, 0, (sizeof *info_ptr));
448893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
449893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following API is not called internally */
451893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid PNGAPI
452b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,
4537a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int freer, png_uint_32 mask)
454893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
4554215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   png_debug(1, "in png_data_freer");
4565f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
457893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (png_ptr == NULL || info_ptr == NULL)
458893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      return;
4595f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4604215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   if (freer == PNG_DESTROY_WILL_FREE_DATA)
461893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      info_ptr->free_me |= mask;
462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4634215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   else if (freer == PNG_USER_WILL_FREE_DATA)
464893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      info_ptr->free_me &= ~mask;
465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
466893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   else
467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_error(png_ptr, "Unknown freer parameter in png_data_freer");
468893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
469893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
470893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid PNGAPI
471b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask,
4727a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int num)
473893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
4744215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   png_debug(1, "in png_free_data");
4755f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
476893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   if (png_ptr == NULL || info_ptr == NULL)
477893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      return;
478893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
4795f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_TEXT_SUPPORTED
480a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free text item num or (if num == -1) all text items */
4813cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   if (info_ptr->text != NULL &&
4829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
483893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
484a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      if (num != -1)
485a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
4869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_free(png_ptr, info_ptr->text[num].key);
4879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->text[num].key = NULL;
488a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
490a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      else
491a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
492a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         int i;
4939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
494a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         for (i = 0; i < info_ptr->num_text; i++)
4959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            png_free(png_ptr, info_ptr->text[i].key);
4969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
497a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         png_free(png_ptr, info_ptr->text);
498a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         info_ptr->text = NULL;
4999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->num_text = 0;
5003cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         info_ptr->max_text = 0;
501a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
502893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
503893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
504893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
5055f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_tRNS_SUPPORTED
506a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any tRNS entry */
5079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0)
508a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
5099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      info_ptr->valid &= ~PNG_INFO_tRNS;
510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_free(png_ptr, info_ptr->trans_alpha);
511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      info_ptr->trans_alpha = NULL;
5129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      info_ptr->num_trans = 0;
513a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
514893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
515893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
5165f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_sCAL_SUPPORTED
517a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any sCAL entry */
5189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0)
519a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
520a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->scal_s_width);
521a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->scal_s_height);
522a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->scal_s_width = NULL;
523a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->scal_s_height = NULL;
524a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_sCAL;
525a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
526893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
527893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
5285f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_pCAL_SUPPORTED
529a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any pCAL entry */
5309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
531a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
532a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->pcal_purpose);
533a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->pcal_units);
534a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->pcal_purpose = NULL;
535a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->pcal_units = NULL;
5369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
537a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      if (info_ptr->pcal_params != NULL)
538a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         {
5399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            int i;
5409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            for (i = 0; i < info_ptr->pcal_nparams; i++)
542a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott               png_free(png_ptr, info_ptr->pcal_params[i]);
5439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
544a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott            png_free(png_ptr, info_ptr->pcal_params);
545a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott            info_ptr->pcal_params = NULL;
546a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         }
547a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_pCAL;
548a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
549893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
550893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
5515f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_iCCP_SUPPORTED
552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Free any profile entry */
5539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0)
554a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
555a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->iccp_name);
556a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->iccp_profile);
557a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->iccp_name = NULL;
558a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->iccp_profile = NULL;
559a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_iCCP;
560a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
561893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
562893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
5635f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_sPLT_SUPPORTED
564a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free a given sPLT entry, or (if num == -1) all sPLT entries */
5653cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   if (info_ptr->splt_palettes != NULL &&
5669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
567893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
568a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      if (num != -1)
569893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      {
5709b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_free(png_ptr, info_ptr->splt_palettes[num].name);
5719b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_free(png_ptr, info_ptr->splt_palettes[num].entries);
5729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->splt_palettes[num].name = NULL;
5739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->splt_palettes[num].entries = NULL;
574a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
576a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      else
577a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
5789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         int i;
579a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott
5809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         for (i = 0; i < info_ptr->splt_palettes_num; i++)
5819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         {
5829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            png_free(png_ptr, info_ptr->splt_palettes[i].name);
5839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            png_free(png_ptr, info_ptr->splt_palettes[i].entries);
584a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         }
5859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
5869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_free(png_ptr, info_ptr->splt_palettes);
5879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->splt_palettes = NULL;
5889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->splt_palettes_num = 0;
589a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         info_ptr->valid &= ~PNG_INFO_sPLT;
590893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project      }
591893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
592893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
593893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
5953cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   if (info_ptr->unknown_chunks != NULL &&
5969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
597893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
598a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      if (num != -1)
599a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
6009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          png_free(png_ptr, info_ptr->unknown_chunks[num].data);
6019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          info_ptr->unknown_chunks[num].data = NULL;
602a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
604a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      else
605a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
606a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         int i;
607893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
6089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         for (i = 0; i < info_ptr->unknown_chunks_num; i++)
6099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            png_free(png_ptr, info_ptr->unknown_chunks[i].data);
610893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
6119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         png_free(png_ptr, info_ptr->unknown_chunks);
6129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->unknown_chunks = NULL;
6139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->unknown_chunks_num = 0;
614a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
615893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
616893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
617893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
6183cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#ifdef PNG_eXIf_SUPPORTED
6193cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   /* Free any eXIf entry */
6203cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0)
6213cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   {
6223cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III# ifdef PNG_READ_eXIf_SUPPORTED
6233cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      if (info_ptr->eXIf_buf)
6243cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      {
6253cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         png_free(png_ptr, info_ptr->eXIf_buf);
6263cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         info_ptr->eXIf_buf = NULL;
6273cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      }
6283cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III# endif
6293cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      if (info_ptr->exif)
6303cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      {
6313cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         png_free(png_ptr, info_ptr->exif);
6323cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         info_ptr->exif = NULL;
6333cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      }
6343cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      info_ptr->valid &= ~PNG_INFO_eXIf;
6353cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   }
6363cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif
6373cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III
6385f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_hIST_SUPPORTED
639a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any hIST entry */
6409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)
641a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
642a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      png_free(png_ptr, info_ptr->hist);
643a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->hist = NULL;
644a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_hIST;
645a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
646893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
647893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
648a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any PLTE entry that was internally allocated */
6499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0)
650a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_free(png_ptr, info_ptr->palette);
652a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->palette = NULL;
653a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_PLTE;
654a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->num_palette = 0;
655a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
656893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
6575f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_INFO_IMAGE_SUPPORTED
658a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Free any image bits attached to the info structure */
6599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
660a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   {
6613cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      if (info_ptr->row_pointers != NULL)
662a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      {
663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_uint_32 row;
664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         for (row = 0; row < info_ptr->height; row++)
665a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott            png_free(png_ptr, info_ptr->row_pointers[row]);
6669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
667a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott         png_free(png_ptr, info_ptr->row_pointers);
6685f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott         info_ptr->row_pointers = NULL;
669a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      }
670a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      info_ptr->valid &= ~PNG_INFO_IDAT;
671a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   }
672893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#endif
673893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (num != -1)
675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      mask &= ~PNG_FREE_MUL;
676893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   info_ptr->free_me &= ~mask;
678893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
6799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ || WRITE */
680893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
681893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* This function returns a pointer to the io_ptr associated with the user
682893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * functions.  The application should free any memory associated with this
683893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * pointer before png_write_destroy() or png_read_destroy() are called.
684893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
685893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectpng_voidp PNGAPI
686b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_get_io_ptr(png_const_structrp png_ptr)
687893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
688a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
689a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return (NULL);
690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
691893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   return (png_ptr->io_ptr);
692893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
693893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
694893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_STDIO_SUPPORTED
696893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Initialize the default input/output functions for the PNG file.  If you
697893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * use your own read or write routines, you can call either png_set_read_fn()
698893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * or png_set_write_fn() instead of png_init_io().  If you have defined
699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a
700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * function of your own because "FILE *" isn't necessarily available.
701893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
702893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectvoid PNGAPI
703b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_init_io(png_structrp png_ptr, png_FILE_p fp)
704893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
7054215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project   png_debug(1, "in png_init_io");
7065f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
707a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
708a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return;
7095f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
710893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   png_ptr->io_ptr = (png_voidp)fp;
711893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
7149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#  ifdef PNG_SAVE_INT_32_SUPPORTED
7159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* PNG signed integers are saved in 32-bit 2's complement format.  ANSI C-90
7169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * defines a cast of a signed integer to an unsigned integer either to preserve
7179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * the value, if it is positive, or to calculate:
7189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
7199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *     (UNSIGNED_MAX+1) + integer
7209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett *
7219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
7229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * negative integral value is added the result will be an unsigned value
7239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * correspnding to the 2's complement representation.
724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
725b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid PNGAPI
726b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_save_int_32(png_bytep buf, png_int_32 i)
727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
7283cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   png_save_uint_32(buf, (png_uint_32)i);
729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
7309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#  endif
731893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_TIME_RFC1123_SUPPORTED
733893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* Convert the supplied time into an RFC 1123 string suitable for use in
734893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * a "Creation Time" or other text-based time string.
735893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
736b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint PNGAPI
737b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)
738893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
739893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   static PNG_CONST char short_months[12][4] =
740893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project        {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
741893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
742893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (out == NULL)
744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (ptime->year > 9999 /* RFC1123 limitation */ ||
747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       ptime->month == 0    ||  ptime->month > 12  ||
748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       ptime->day   == 0    ||  ptime->day   > 31  ||
749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       ptime->hour  > 23    ||  ptime->minute > 59 ||
750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       ptime->second > 60)
751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
752893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
753893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      size_t pos = 0;
755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      char number_buf[5]; /* enough for a four-digit year */
756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))
758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     define APPEND_NUMBER(format, value)\
759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value)))
760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     define APPEND(ch) if (pos < 28) out[pos++] = (ch)
761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day);
763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND(' ');
764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_STRING(short_months[(ptime->month - 1)]);
765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND(' ');
766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year);
767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND(' ');
768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour);
769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND(':');
770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute);
771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND(':');
772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second);
773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      APPEND_STRING(" +0000"); /* This reliably terminates the buffer */
7749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      PNG_UNUSED (pos)
775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     undef APPEND
777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     undef APPEND_NUMBER
778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     undef APPEND_STRING
779893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
7849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#    if PNG_LIBPNG_VER < 10700
785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* To do: remove the following from libpng-1.7 */
786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Original API that uses a private buffer in png_struct.
787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Deprecated because it causes png_struct to carry a spurious temporary
788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * buffer (png_struct::time_buffer), better to have the caller pass this in.
789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
790b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_const_charp PNGAPI
791b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime)
792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr != NULL)
794893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   {
795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The only failure above if png_ptr != NULL is from an invalid ptime */
7969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0)
797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_warning(png_ptr, "Ignoring invalid time value");
798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_ptr->time_buffer;
801893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   }
802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return NULL;
804893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
8059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#    endif /* LIBPNG_VER < 10700 */
8069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#  endif /* TIME_RFC1123 */
807893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
8089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ || WRITE */
809893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
810b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_const_charp PNGAPI
811b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_get_copyright(png_const_structrp png_ptr)
812893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
8145f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef PNG_STRING_COPYRIGHT
815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_STRING_COPYRIGHT
8165f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#else
817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef __STDC__
818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_STRING_NEWLINE \
8193cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      "libpng version 1.6.34 - September 29, 2017" PNG_STRING_NEWLINE \
8203cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \
821114668651129dc978b9710d0f0ad107ee5ee3281Matt Sarett      PNG_STRING_NEWLINE \
8229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
8239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
8249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      PNG_STRING_NEWLINE;
825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  else
8263cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   return "libpng version 1.6.34 - September 29, 2017\
8273cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\
8285f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott      Copyright (c) 1996-1997 Andreas Dilger\
829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
8315f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#endif
832893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
833893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
834893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* The following return the library version as a short string in the
835893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * format 1.0.0 through 99.99.99zz.  To get the version of *.h files
836893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * used with your application, print out PNG_LIBPNG_VER_STRING, which
837893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * is defined in png.h.
838893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * Note: now there is no difference between png_get_libpng_ver() and
839893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * png_get_header_ver().  Due to the version_nn_nn_nn typedef guard,
840893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project * it is guaranteed that png.c uses the correct version of png.h.
841893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project */
842b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_const_charp PNGAPI
843b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_get_libpng_ver(png_const_structrp png_ptr)
844893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
845893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   /* Version of *.c files used when building libpng */
846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return png_get_header_ver(png_ptr);
847893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
848893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
849b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_const_charp PNGAPI
850b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_get_header_ver(png_const_structrp png_ptr)
851893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
852893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   /* Version of *.h files used when building libpng */
853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_LIBPNG_VER_STRING;
855893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
856893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
857b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_const_charp PNGAPI
858b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_get_header_version(png_const_structrp png_ptr)
859893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
860893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   /* Returns longer string containing both version and date */
861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
8625f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#ifdef __STDC__
863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_HEADER_VERSION_STRING
864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifndef PNG_READ_SUPPORTED
8659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      " (NO READ SUPPORT)"
866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
8679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      PNG_STRING_NEWLINE;
8685f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#else
869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_HEADER_VERSION_STRING;
8705f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#endif
871893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
872893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
873b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
874b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* NOTE: this routine is not used internally! */
875b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari/* Build a grayscale palette.  Palette is assumed to be 1 << bit_depth
876b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * large of png_color.  This lets grayscale images be treated as
877b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * paletted.  Most useful for gamma correction and simplification
878b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari * of code.  This API is not used internally.
879b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari */
880b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurarivoid PNGAPI
881b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraripng_build_grayscale_palette(int bit_depth, png_colorp palette)
882b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari{
883b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int num_palette;
884b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int color_inc;
885b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int i;
886b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   int v;
887b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
888b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   png_debug(1, "in png_do_build_grayscale_palette");
889b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
890b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   if (palette == NULL)
891b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return;
892b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
893b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   switch (bit_depth)
894b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
895b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      case 1:
896b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         num_palette = 2;
897b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_inc = 0xff;
898b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
899b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
900b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      case 2:
901b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         num_palette = 4;
902b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_inc = 0x55;
903b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
904b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
905b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      case 4:
906b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         num_palette = 16;
907b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_inc = 0x11;
908b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
909b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
910b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      case 8:
911b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         num_palette = 256;
912b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_inc = 1;
913b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
914b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
915b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      default:
916b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         num_palette = 0;
917b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         color_inc = 0;
918b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
919b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
920b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
921b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
922b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   {
9239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      palette[i].red = (png_byte)(v & 0xff);
9249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      palette[i].green = (png_byte)(v & 0xff);
9259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      palette[i].blue = (png_byte)(v & 0xff);
926b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   }
927b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari}
928b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif
929b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
931893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectint PNGAPI
932b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name)
933893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
934a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   /* Check chunk_name and return "keep" value if it's on the list, else 0 */
935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_const_bytep p, p_end;
936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0)
938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return PNG_HANDLE_CHUNK_AS_DEFAULT;
939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   p_end = png_ptr->chunk_list;
941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   p = p_end + png_ptr->num_chunk_list*5; /* beyond end */
942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The code is the fifth byte after each four byte string.  Historically this
944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * code was always searched from the end of the list, this is no longer
945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * necessary because the 'set' routine handles duplicate entries correcty.
946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   do /* num_chunk_list > 0, so at least one */
948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      p -= 5;
950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
9519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (memcmp(chunk_name, p, 4) == 0)
952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return p[4];
953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   while (p > p_end);
955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This means that known chunks should be processed and unknown chunks should
957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * be handled according to the value of png_ptr->unknown_default; this can be
958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * confusing because, as a result, there are two levels of defaulting for
959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * unknown chunks.
960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_HANDLE_CHUNK_AS_DEFAULT;
962893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
963893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
964b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\
965b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED)
966b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
967b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name)
968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_byte chunk_string[5];
970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name);
972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return png_handle_as_unknown(png_ptr, chunk_string);
973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
974b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */
975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* SET_UNKNOWN_CHUNKS */
976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
977b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED
978893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* This function, added to libpng-1.0.6g, is untested. */
979893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectint PNGAPI
980b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_reset_zstream(png_structrp png_ptr)
981893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
982a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott   if (png_ptr == NULL)
983a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott      return Z_STREAM_ERROR;
984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* WARNING: this resets the window bits to the maximum! */
986893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   return (inflateReset(&png_ptr->zstream));
987893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
9889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ */
989893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
990893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project/* This function was added to libpng-1.0.7 */
991893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectpng_uint_32 PNGAPI
992893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Projectpng_access_version_number(void)
993893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
994893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project   /* Version of *.c files used when building libpng */
995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return((png_uint_32)PNG_LIBPNG_VER);
996893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project}
997893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project
998893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Ensure that png_ptr->zstream.msg holds some appropriate error message string.
1000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * If it doesn't 'ret' is used to set it to something appropriate, even in cases
1001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * like Z_OK or Z_STREAM_END where the error code is apparently a success code.
1002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1003b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
1004b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_zstream_error(png_structrp png_ptr, int ret)
1005893912bfc2683463dc3e2c445336752d012563d3The Android Open Source Project{
1006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Translate 'ret' into an appropriate error string, priority is given to the
1007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * one in zstream if set.  This always returns a string, even in cases like
1008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Z_OK or Z_STREAM_END where the error code is a success code.
1009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr->zstream.msg == NULL) switch (ret)
1011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
1013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_OK:
1014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code");
1015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10164215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_STREAM_END:
1018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Normal exit */
1019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream");
1020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
1021a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott
1022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_NEED_DICT:
1023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* This means the deflate stream did not have a dictionary; this
1024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * indicates a bogus PNG.
1025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
1026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary");
1027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
1028a0bb96c34e65378853ee518bac502842d26c2d1aPatrick Scott
1029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_ERRNO:
1030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* gz APIs only: should not happen */
1031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error");
1032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10334215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_STREAM_ERROR:
1035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* internal libpng error */
1036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib");
1037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10385f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
1039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_DATA_ERROR:
1040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream");
1041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10424215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_MEM_ERROR:
1044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory");
1045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10464215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_BUF_ERROR:
1048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* End of input or output; not a problem if the caller is doing
1049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * incremental read or write.
1050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
1051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated");
1052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10534215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case Z_VERSION_ERROR:
1055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version");
1056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
10574215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project
1058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_UNEXPECTED_ZLIB_RETURN:
1059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Compile errors here mean that zlib now uses the value co-opted in
1060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above
1061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * and change pngpriv.h.  Note that this message is "... return",
1062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * whereas the default/Z_OK one is "... return code".
1063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
1064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return");
1065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
1066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
10674215dd1533c56e1a89ae6f1d6ea68677fac27fdaThe Android Open Source Project}
10685f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
1069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* png_convert_size: a PNGAPI but no longer in png.h, so deleted
1070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * at libpng 1.5.5!
1071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */
1074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */
1075b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1076b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_check_gamma(png_const_structrp png_ptr,
10777a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, png_fixed_point gAMA, int from)
1078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This is called to check a new gamma value against an existing one.  The
1079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * routine returns false if the new gamma value should not be written.
1080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 'from' says where the new gamma value comes from:
1082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    0: the new gamma value is the libpng estimate for an ICC profile
1084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    1: the new gamma value comes from a gAMA chunk
1085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    2: the new gamma value comes from an sRGB chunk
1086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
10875f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott{
1088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point gtest;
1089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 &&
10917a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       (png_muldiv(&gtest, colorspace->gamma, PNG_FP_1, gAMA) == 0  ||
10929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_gamma_significant(gtest) != 0))
1093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Either this is an sRGB image, in which case the calculated gamma
1095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * approximation should match, or this is an image with a profile and the
1096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * value libpng calculates for the gamma of the profile does not match the
1097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * value recorded in the file.  The former, sRGB, case is an error, the
1098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * latter is just a warning.
1099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
1100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2)
1101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
1102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_chunk_report(png_ptr, "gamma value does not match sRGB",
11037a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             PNG_CHUNK_ERROR);
1104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Do not overwrite an sRGB value */
1105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return from == 2;
1106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
1107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else /* sRGB tag not involved */
1109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
1110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_chunk_report(png_ptr, "gamma value does not match libpng estimate",
11117a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             PNG_CHUNK_WARNING);
1112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return from == 1;
1113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
1114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
1117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1119b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
1120b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_gamma(png_const_structrp png_ptr,
11217a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, png_fixed_point gAMA)
1122b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
11249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * occur.  Since the fixed point representation is asymetrical it is
1125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * possible for 1/gamma to overflow the limit of 21474 and this means the
1126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * gamma value must be at least 5/100000 and hence at most 20000.0.  For
1127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * safety the limits here are a little narrower.  The values are 0.00016 to
1128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 6250.0, which are truly ridiculous gamma values (and will produce
1129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * displays that are all black or all white.)
1130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk
1132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * handling code, which only required the value to be >0.
1133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_const_charp errmsg;
1135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (gAMA < 16 || gAMA > 625000000)
1137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      errmsg = "gamma value out of range";
1138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_READ_gAMA_SUPPORTED
11409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* Allow the application to set the gamma value more than once */
11419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
11429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0)
11439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      errmsg = "duplicate";
1144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
1145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Do nothing if the colorspace is already invalid */
11479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return;
1149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
1151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
11529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA,
11539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          1/*from gAMA*/) != 0)
1154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
1155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Store this gamma value. */
1156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->gamma = gAMA;
1157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |=
1158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA);
1159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
1160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* At present if the check_gamma test fails the gamma of the colorspace is
1162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * not updated however the colorspace is not invalidated.  This
1163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * corresponds to the case where the existing gamma comes from an sRGB
1164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * chunk or profile.  An error message has already been output.
1165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
1166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return;
1167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Error exit - errmsg has been set. */
1170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |= PNG_COLORSPACE_INVALID;
1171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR);
1172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1174b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
1175b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr)
1176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
11779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0)
1178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Everything is invalid */
1180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB|
1181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         PNG_INFO_iCCP);
1182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_COLORSPACE_SUPPORTED
11849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* Clean up the iCCP profile now if it won't be used. */
11859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/);
1186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     else
11879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      PNG_UNUSED(png_ptr)
1188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
1189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
1192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_COLORSPACE_SUPPORTED
11949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      /* Leave the INFO_iCCP flag set if the pngset.c code has already set
11959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * it; this allows a PNG to contain a profile which matches sRGB and
11969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       * yet still have that profile retrievable by the application.
11979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       */
11989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0)
11999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->valid |= PNG_INFO_sRGB;
1200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
12019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      else
12029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->valid &= ~PNG_INFO_sRGB;
1203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
12049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
12059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->valid |= PNG_INFO_cHRM;
1206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
12079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      else
12089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         info_ptr->valid &= ~PNG_INFO_cHRM;
1209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
1210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
12119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0)
1212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         info_ptr->valid |= PNG_INFO_gAMA;
1213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
1215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         info_ptr->valid &= ~PNG_INFO_gAMA;
1216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_SUPPORTED
1220b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
1221b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr)
1222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (info_ptr == NULL) /* reduce code size; check here not in the caller */
1224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return;
1225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   info_ptr->colorspace = png_ptr->colorspace;
1227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_colorspace_sync_info(png_ptr, info_ptr);
1228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1229b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
12309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* GAMMA */
1231b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_COLORSPACE_SUPPORTED
1233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for
1234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * cHRM, as opposed to using chromaticities.  These internal APIs return
1235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * non-zero on a parameter error.  The X, Y and Z values are required to be
1236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * positive and less than 1.0.
1237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1238b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1239b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
1240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_int_32 d, dwhite, whiteX, whiteY;
1242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z;
12449b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0)
12459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
12469b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0)
12479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   dwhite = d;
1249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteX = XYZ->red_X;
1250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteY = XYZ->red_Y;
1251b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z;
12539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0)
12549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
12559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0)
12569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   dwhite += d;
1258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteX += XYZ->green_X;
1259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteY += XYZ->green_Y;
1260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z;
12629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0)
12639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
12649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0)
12659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   dwhite += d;
1267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteX += XYZ->blue_X;
1268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   whiteY += XYZ->blue_Y;
1269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The reference white is simply the sum of the end-point (X,Y,Z) vectors,
1271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * thus:
1272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
12739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0)
12749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
12759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0)
12769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
1279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1281b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1282b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
1283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point red_inverse, green_inverse, blue_scale;
1285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point left, right, denominator;
1286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Check xy and, implicitly, z.  Note that wide gamut color spaces typically
1288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * have end points with 0 tristimulus values (these are impossible end
1289ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris    * points, but they are used to cover the possible colors).  We check
1290ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris    * xy->whitey against 5, not 0, to avoid a possible integer overflow.
1291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1292ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris   if (xy->redx   < 0 || xy->redx > PNG_FP_1) return 1;
1293ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris   if (xy->redy   < 0 || xy->redy > PNG_FP_1-xy->redx) return 1;
1294b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1;
1295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1;
1296ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris   if (xy->bluex  < 0 || xy->bluex > PNG_FP_1) return 1;
1297ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris   if (xy->bluey  < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1;
1298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1;
1299ee604d7c8d1b52e83c0fde589eb76973b0e06304Christopher Ferris   if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1;
1300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The reverse calculation is more difficult because the original tristimulus
1302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
1303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * derived values were recorded in the cHRM chunk;
1304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * (red,green,blue,white)x(x,y).  This loses one degree of freedom and
1305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * therefore an arbitrary ninth value has to be introduced to undo the
1306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * original transformations.
1307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Think of the original end-points as points in (X,Y,Z) space.  The
1309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * chromaticity values (c) have the property:
1310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *           C
1312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *   c = ---------
1313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *       X + Y + Z
1314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * For each c (x,y,z) from the corresponding original C (X,Y,Z).  Thus the
1316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * three chromaticity values (x,y,z) for each end-point obey the
1317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * relationship:
1318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *   x + y + z = 1
1320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * This describes the plane in (X,Y,Z) space that intersects each axis at the
1322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * value 1.0; call this the chromaticity plane.  Thus the chromaticity
1323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * calculation has scaled each end-point so that it is on the x+y+z=1 plane
1324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * and chromaticity is the intersection of the vector from the origin to the
1325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * (X,Y,Z) value with the chromaticity plane.
1326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * To fully invert the chromaticity calculation we would need the three
1328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * end-point scale factors, (red-scale, green-scale, blue-scale), but these
1329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * were not recorded.  Instead we calculated the reference white (X,Y,Z) and
1330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * recorded the chromaticity of this.  The reference white (X,Y,Z) would have
1331b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * given all three of the scale factors since:
1332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    color-C = color-c * color-scale
1334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-C = red-C + green-C + blue-C
1335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1337b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * But cHRM records only white-x and white-y, so we have lost the white scale
1338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * factor:
1339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-C = white-c*white-scale
1341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * To handle this the inverse transformation makes an arbitrary assumption
1343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * about white-scale:
1344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    Assume: white-Y = 1.0
1346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    Hence:  white-scale = 1/white-y
1347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    Or:     red-Y + green-Y + blue-Y = 1.0
1348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Notice the last statement of the assumption gives an equation in three of
1350b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the nine values we want to calculate.  8 more equations come from the
1351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * above routine as summarised at the top above (the chromaticity
1352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * calculation):
1353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    Given: color-x = color-X / (color-X + color-Y + color-Z)
1355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0
1356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * This is 9 simultaneous equations in the 9 variables "color-C" and can be
1358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * solved by Cramer's rule.  Cramer's rule requires calculating 10 9x9 matrix
1359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * determinants, however this is not as bad as it seems because only 28 of
1360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the total of 90 terms in the various matrices are non-zero.  Nevertheless
1361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Cramer's rule is notoriously numerically unstable because the determinant
1362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * calculation involves the difference of large, but similar, numbers.  It is
1363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * difficult to be sure that the calculation is stable for real world values
1364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * and it is certain that it becomes unstable where the end points are close
1365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * together.
1366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * So this code uses the perhaps slightly less optimal but more
1368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * understandable and totally obvious approach of calculating color-scale.
1369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * This algorithm depends on the precision in white-scale and that is
1371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * (1/white-y), so we can immediately see that as white-y approaches 0 the
1372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * accuracy inherent in the cHRM chunk drops off substantially.
1373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
13749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * libpng arithmetic: a simple inversion of the above equations
1375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * ------------------------------------------------------------
1376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white_scale = 1/white-y
1378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-X = white-x * white-scale
1379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-Y = 1.0
1380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-Z = (1 - white-x - white-y) * white_scale
1381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    white-C = red-C + green-C + blue-C
1383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *            = red-c*red-scale + green-c*green-scale + blue-c*blue-scale
1384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * This gives us three equations in (red-scale,green-scale,blue-scale) where
1386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * all the coefficients are now known:
1387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-x*red-scale + green-x*green-scale + blue-x*blue-scale
1389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *       = white-x/white-y
1390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1
1391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-z*red-scale + green-z*green-scale + blue-z*blue-scale
1392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *       = (1 - white-x - white-y)/white-y
1393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * In the last equation color-z is (1 - color-x - color-y) so we can add all
1395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * three equations together to get an alternative third:
1396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-scale + green-scale + blue-scale = 1/white-y = white-scale
1398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * So now we have a Cramer's rule solution where the determinants are just
1400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
1401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * multiplication of three coefficients so we can't guarantee to avoid
1402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * overflow in the libpng fixed point representation.  Using Cramer's rule in
1403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * floating point is probably a good choice here, but it's not an option for
1404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * fixed point.  Instead proceed to simplify the first two equations by
1405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * eliminating what is likely to be the largest value, blue-scale:
1406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    blue-scale = white-scale - red-scale - green-scale
1408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Hence:
1410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale =
1412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                (white-x - blue-x)*white-scale
1413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale =
1415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                1 - blue-y*white-scale
1416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * And now we can trivially solve for (red-scale,green-scale):
1418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    green-scale =
1420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale
1421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                -----------------------------------------------------------
1422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                                  green-x - blue-x
1423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-scale =
1425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                1 - blue-y*white-scale - (green-y - blue-y) * green-scale
1426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                ---------------------------------------------------------
1427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *                                  red-y - blue-y
1428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Hence:
1430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    red-scale =
1432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *          ( (green-x - blue-x) * (white-y - blue-y) -
1433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *            (green-y - blue-y) * (white-x - blue-x) ) / white-y
1434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * -------------------------------------------------------------------------
1435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    green-scale =
1438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *          ( (red-y - blue-y) * (white-x - blue-x) -
1439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *            (red-x - blue-x) * (white-y - blue-y) ) / white-y
1440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * -------------------------------------------------------------------------
1441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x)
1442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Accuracy:
1444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * The input values have 5 decimal digits of accuracy.  The values are all in
1445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the range 0 < value < 1, so simple products are in the same range but may
1446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * need up to 10 decimal digits to preserve the original precision and avoid
1447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * underflow.  Because we are using a 32-bit signed representation we cannot
1448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * match this; the best is a little over 9 decimal digits, less than 10.
1449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * The approach used here is to preserve the maximum precision within the
1451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * signed representation.  Because the red-scale calculation above uses the
1452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * difference between two products of values that must be in the range -1..+1
1453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * it is sufficient to divide the product by 7; ceil(100,000/32767*2).  The
1454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * factor is irrelevant in the calculation because it is applied to both
1455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * numerator and denominator.
1456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Note that the values of the differences of the products of the
1458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * chromaticities in the above equations tend to be small, for example for
1459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the sRGB chromaticities they are:
1460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * red numerator:    -0.04751
1462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * green numerator:  -0.08788
1463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * denominator:      -0.2241 (without white-y multiplication)
1464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  The resultant Y coefficients from the chromaticities of some widely used
1466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  color space definitions are (to 15 decimal places):
1467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  sRGB
1469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    0.212639005871510 0.715168678767756 0.072192315360734
1470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  Kodak ProPhoto
1471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    0.288071128229293 0.711843217810102 0.000085653960605
1472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  Adobe RGB
1473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    0.297344975250536 0.627363566255466 0.075291458493998
1474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *  Adobe Wide Gamut RGB
1475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    0.258728243040113 0.724682314948566 0.016589442011321
1476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* By the argument, above overflow should be impossible here. The return
1478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * value of 2 indicates an internal error to the caller.
1479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
14809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0)
1481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
14829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0)
1483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
1484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   denominator = left - right;
1485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Now find the red numerator. */
14879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
14899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
1491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Overflow is possible here and it indicates an extreme set of PNG cHRM
1493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * chunk values.  This calculation actually returns the reciprocal of the
1494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * scale value because this allows us to delay the multiplication of white-y
1495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * into the denominator, which tends to produce a small number.
1496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
14979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 ||
1498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       red_inverse <= xy->whitey /* r+g+b scales = white scale */)
1499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Similarly for green_inverse: */
15029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0)
1503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
15049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0)
1505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 2;
15069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 ||
1507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       green_inverse <= xy->whitey)
1508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* And the blue scale, the checks above guarantee this can't overflow but it
1511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * can still produce 0 for extreme cHRM values.
1512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) -
15149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       png_reciprocal(green_inverse);
15159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (blue_scale <= 0)
15169b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* And fill in the png_XYZ: */
15209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0)
15219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
15229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0)
15239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
15249b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1,
15259b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       red_inverse) == 0)
1526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
15289b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0)
1529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
15309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0)
1531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
15329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1,
15339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       green_inverse) == 0)
1534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
15369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0)
15379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
15389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0)
15399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
15409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale,
15419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_FP_1) == 0)
1542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /*success*/
1545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1547b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1548b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_XYZ_normalize(png_XYZ *XYZ)
1549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_int_32 Y;
1551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 ||
1553b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 ||
1554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0)
1555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
1556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1.
1558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore
1559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * relying on addition of two positive values producing a negative one is not
1560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * safe.
1561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   Y = XYZ->red_Y;
15639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (0x7fffffff - Y < XYZ->green_X)
15649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   Y += XYZ->green_Y;
15669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (0x7fffffff - Y < XYZ->blue_X)
15679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 1;
1568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   Y += XYZ->blue_Y;
1569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (Y != PNG_FP_1)
1571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
15729b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0)
15739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0)
15759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0)
15779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
1578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
15799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0)
15809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0)
15829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0)
15849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
1585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
15869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0)
15879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0)
15899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
15909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0)
15919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return 1;
1592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
1595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1597b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1598b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta)
1599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Allow an error of +/-0.01 (absolute value) on each chromaticity */
16019b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) ||
16029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) ||
16039b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->redx,   xy2->redx,  delta) ||
16049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->redy,   xy2->redy,  delta) ||
16059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) ||
16069b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) ||
16079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->bluex,  xy2->bluex, delta) ||
16089b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       PNG_OUT_OF_RANGE(xy1->bluey,  xy2->bluey, delta))
16099b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 0;
16109b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return 1;
1611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM
1614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * chunk chromaticities.  Earlier checks used to simply look for the overflow
1615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * condition (where the determinant of the matrix to solve for XYZ ends up zero
1616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * because the chromaticity values are not all distinct.)  Despite this it is
1617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * theoretically possible to produce chromaticities that are apparently valid
1618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * but that rapidly degrade to invalid, potentially crashing, sets because of
1619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * arithmetic inaccuracies when calculations are performed on them.  The new
1620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * check is to round-trip xy -> XYZ -> xy and then check that the result is
1621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * within a small percentage of the original.
1622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1623b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1624b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy)
1625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int result;
1627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_xy xy_test;
1628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* As a side-effect this routine also returns the XYZ endpoints. */
1630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   result = png_XYZ_from_xy(XYZ, xy);
16319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (result != 0)
16329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return result;
1633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   result = png_xy_from_XYZ(&xy_test, XYZ);
16359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (result != 0)
16369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return result;
1637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_colorspace_endpoints_match(xy, &xy_test,
16399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       5/*actually, the math is pretty accurate*/) != 0)
1640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
1641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Too much slip */
1643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
1644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is the check going the other way.  The XYZ is modified to normalize it
1647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (another side-effect) and the xy chromaticities are returned.
1648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1649b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1650b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ)
1651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int result;
1653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_XYZ XYZtemp;
1654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   result = png_XYZ_normalize(XYZ);
16569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (result != 0)
16579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return result;
1658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   result = png_xy_from_XYZ(xy, XYZ);
16609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (result != 0)
16619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return result;
1662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   XYZtemp = *XYZ;
1664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return png_colorspace_check_xy(&XYZtemp, xy);
1665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Used to check for an endpoint match against sRGB */
1668b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic const png_xy sRGB_xy = /* From ITU-R BT.709-3 */
1669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* color      x       y */
1671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* red   */ 64000, 33000,
1672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* green */ 30000, 60000,
1673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* blue  */ 15000,  6000,
1674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* white */ 31270, 32900
1675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
1676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1677b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1678b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr,
16797a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ,
16807a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int preferred)
1681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
16829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
1684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The consistency check is performed on the chromaticities; this factors out
1686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * variations because of the normalization (or not) of the end point Y
1687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * values.
1688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
16899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (preferred < 2 &&
16909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
1691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The end points must be reasonably close to any we already have.  The
1693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * following allows an error of up to +/-.001
1694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
16959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy,
16969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          100) == 0)
1697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
1698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |= PNG_COLORSPACE_INVALID;
1699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_benign_error(png_ptr, "inconsistent chromaticities");
1700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return 0; /* failed */
1701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
1702b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Only overwrite with preferred values */
17049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (preferred == 0)
1705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return 1; /* ok, but no change */
1706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->end_points_xy = *xy;
1709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->end_points_XYZ = *XYZ;
1710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS;
1711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The end points are normally quoted to two decimal digits, so allow +/-0.01
1713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * on this test.
1714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
17159b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0)
1716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB;
1717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
1719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      colorspace->flags &= PNG_COLORSPACE_CANCEL(
1720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
1721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 2; /* ok and changed */
1723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1725b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
1726b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_chromaticities(png_const_structrp png_ptr,
17277a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, const png_xy *xy, int preferred)
1728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* We must check the end points to ensure they are reasonable - in the past
1730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * color management systems have crashed as a result of getting bogus
1731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * colorant values, while this isn't the fault of libpng it is the
1732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * responsibility of libpng because PNG carries the bomb and libpng is in a
1733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * position to protect against it.
1734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_XYZ XYZ;
1736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   switch (png_colorspace_check_xy(&XYZ, xy))
1738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0: /* success */
1740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ,
17417a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             preferred);
1742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 1:
1744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* We can't invert the chromaticities so we can't produce value XYZ
1745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * values.  Likely as not a color management system will fail too.
1746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
1747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |= PNG_COLORSPACE_INVALID;
1748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_benign_error(png_ptr, "invalid chromaticities");
1749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
1750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
1752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* libpng is broken; this should be a warning but if it happens we
1753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * want error reports so for the moment it is an error.
1754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
1755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |= PNG_COLORSPACE_INVALID;
1756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_error(png_ptr, "internal error checking chromaticities");
1757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* failed */
1760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1762b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
1763b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_endpoints(png_const_structrp png_ptr,
17647a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred)
1765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_XYZ XYZ = *XYZ_in;
1767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_xy xy;
1768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   switch (png_colorspace_check_XYZ(&xy, &XYZ))
1770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0:
1772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ,
17737a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             preferred);
1774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 1:
1776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* End points are invalid. */
1777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |= PNG_COLORSPACE_INVALID;
1778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_benign_error(png_ptr, "invalid end points");
1779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
1780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
1782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         colorspace->flags |= PNG_COLORSPACE_INVALID;
1783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_error(png_ptr, "internal error checking chromaticities");
1784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* failed */
1787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED)
1790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Error message generation */
1791b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic char
1792b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_tag_char(png_uint_32 byte)
1793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   byte &= 0xff;
1795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (byte >= 32 && byte <= 126)
1796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return (char)byte;
1797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
1798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return '?';
1799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1801b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void
1802b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_tag_name(char *name, png_uint_32 tag)
1803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[0] = '\'';
1805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[1] = png_icc_tag_char(tag >> 24);
1806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[2] = png_icc_tag_char(tag >> 16);
1807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[3] = png_icc_tag_char(tag >>  8);
1808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[4] = png_icc_tag_char(tag      );
1809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   name[5] = '\'';
1810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1812b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1813b50c217251b086440efcdb273c22f86a06c80cbaChris Craikis_ICC_signature_char(png_alloc_size_t it)
1814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) ||
1816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (it >= 97 && it <= 122);
1817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1819b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripuraristatic int
1820b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurariis_ICC_signature(png_alloc_size_t it)
1821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return is_ICC_signature_char(it >> 24) /* checks all the top bits */ &&
1823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      is_ICC_signature_char((it >> 16) & 0xff) &&
1824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      is_ICC_signature_char((it >> 8) & 0xff) &&
1825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      is_ICC_signature_char(it & 0xff);
1826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1828b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
1829b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
18307a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_alloc_size_t value, png_const_charp reason)
1831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1832b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   size_t pos;
1833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   char message[196]; /* see below for calculation */
1834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (colorspace != NULL)
1836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      colorspace->flags |= PNG_COLORSPACE_INVALID;
1837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */
1839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */
1840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */
18419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (is_ICC_signature(value) != 0)
1842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* So 'value' is at most 4 bytes and the following cast is safe */
1844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_icc_tag_name(message+pos, (png_uint_32)value);
1845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      pos += 6; /* total +8; less than the else clause */
1846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      message[pos++] = ':';
1847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      message[pos++] = ' ';
1848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_WARNINGS_SUPPORTED
1850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
1851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
1852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/
1853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         pos = png_safecat(message, (sizeof message), pos,
18557a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_format_number(number, number+(sizeof number),
18567a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             PNG_NUMBER_FORMAT_x, value));
1857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/
1858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
1859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
1860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The 'reason' is an arbitrary message, allow +79 maximum 195 */
1861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   pos = png_safecat(message, (sizeof message), pos, reason);
1862b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari   PNG_UNUSED(pos)
1863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This is recoverable, but make it unconditionally an app_error on write to
18659b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * avoid writing invalid ICC profiles into PNG files (i.e., we handle them
1866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * on read, with a warning, but on write unless the app turns off
1867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * application errors the PNG won't be written.)
1868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_chunk_report(png_ptr, message,
18707a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR);
1871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
1873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* sRGB || iCCP */
1875b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_sRGB_SUPPORTED
1877b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
1878b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace,
18797a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int intent)
1880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* sRGB sets known gamma, end points and (from the chunk) intent. */
1882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* IMPORTANT: these are not necessarily the values found in an ICC profile
1883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * because ICC profiles store values adapted to a D50 environment; it is
18849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * expected that the ICC profile mediaWhitePointTag will be D50; see the
1885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * checks and code elsewhere to understand this better.
1886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
1887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * These XYZ values, which are accurate to 5dp, produce rgb to gray
1888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * coefficients of (6968,23435,2366), which are reduced (because they add up
1889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * to 32769 not 32768) to (6968,23434,2366).  These are the values that
1890b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * libpng has traditionally used (and are the best values given the 15bit
1891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * algorithm used by the rgb to gray code.)
1892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */
1894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* color      X      Y      Z */
1896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* red   */ 41239, 21264,  1933,
1897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* green */ 35758, 71517, 11919,
1898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* blue  */ 18048,  7219, 95053
1899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   };
1900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Do nothing if the colorspace is already invalidated. */
19029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
1903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
1904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1905b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Check the intent, then check for existing settings.  It is valid for the
1906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must
1907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * be consistent with the correct values.  If, however, this function is
1908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * called below because an iCCP chunk matches sRGB then it is quite
1909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * conceivable that an older app recorded incorrect gAMA and cHRM because of
1910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * an incorrect calculation based on the values in the profile - this does
1911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * *not* invalidate the profile (though it still produces an error, which can
1912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * be ignored.)
1913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST)
1915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, "sRGB",
19163cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III          (png_alloc_size_t)intent, "invalid sRGB rendering intent");
1917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 &&
19197a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       colorspace->rendering_intent != intent)
1920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, "sRGB",
19213cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         (png_alloc_size_t)intent, "inconsistent rendering intents");
1922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0)
1924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
1925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_benign_error(png_ptr, "duplicate sRGB information ignored");
1926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
1927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
1928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* If the standard sRGB cHRM chunk does not match the one from the PNG file
1930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * warn but overwrite the value with the correct one.
1931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 &&
19337a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy,
19347a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       100))
1935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_chunk_report(png_ptr, "cHRM chunk does not match sRGB",
1936b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         PNG_CHUNK_ERROR);
1937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This check is just done for the error reporting - the routine always
1939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * returns true when the 'from' argument corresponds to sRGB (2).
1940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
1941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE,
19427a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       2/*from sRGB*/);
1943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* intent: bugs in GCC force 'int' to be used as the parameter type. */
1945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->rendering_intent = (png_uint_16)intent;
1946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT;
1947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* endpoints */
1949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->end_points_xy = sRGB_xy;
1950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->end_points_XYZ = sRGB_XYZ;
1951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |=
1952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB);
1953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* gamma */
1955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->gamma = PNG_GAMMA_sRGB_INVERSE;
1956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA;
1957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Finally record that we have an sRGB profile */
1959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   colorspace->flags |=
1960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB);
1961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1962b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1; /* set */
1963b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* sRGB */
1965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
1966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_iCCP_SUPPORTED
1967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Encoded value of D50 as an ICC XYZNumber.  From the ICC 2010 spec the value
1968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is XYZ(0.9642,1.0,0.8249), which scales to:
1969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
1970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *    (63189.8112, 65536, 54060.6464)
1971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
1972b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic const png_byte D50_nCIEXYZ[12] =
1973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d };
1974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
19757a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidisstatic int /* bool */
19767a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidisicc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
19777a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_uint_32 profile_length)
1978b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
1979b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (profile_length < 132)
1980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
19817a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "too short");
1982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
1983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
1984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
19857a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#ifdef PNG_READ_iCCP_SUPPORTED
19867a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidisint /* PRIVATE */
19877a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidispng_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace,
19887a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_uint_32 profile_length)
19897a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis{
19907a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   if (!icc_check_length(png_ptr, colorspace, name, profile_length))
19917a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      return 0;
19927a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
19937a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   /* This needs to be here because the 'normal' check is in
19947a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * png_decompress_chunk, yet this happens after the attempt to
19957a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * png_malloc_base the required data.  We only need this on read; on write
19967a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * the caller supplies the profile buffer so libpng doesn't allocate it.  See
19977a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * the call to icc_check_length below (the write case).
19987a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    */
19997a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
20007a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else if (png_ptr->user_chunk_malloc_max > 0 &&
20017a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis               png_ptr->user_chunk_malloc_max < profile_length)
20027a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
20037a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "exceeds application limits");
20047a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#  elif PNG_USER_CHUNK_MALLOC_MAX > 0
20057a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length)
20067a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
20077a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "exceeds libpng limits");
20087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#  else /* !SET_USER_LIMITS */
20097a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      /* This will get compiled out on all 32-bit and better systems. */
20107a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else if (PNG_SIZE_MAX < profile_length)
20117a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
20127a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "exceeds system limits");
20137a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#  endif /* !SET_USER_LIMITS */
20147a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
20157a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   return 1;
20167a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis}
20177a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#endif /* READ_iCCP */
20187a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
2019b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
2020b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace,
20217a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_uint_32 profile_length,
20227a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_bytep profile/* first 132 bytes only */, int color_type)
2023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 temp;
2025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Length check; this cannot be ignored in this code because profile_length
2027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * is used later to check the tag table, so even if the profile seems over
2028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * long profile_length from the caller must be correct.  The caller can fix
2029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * this up on read or write by just passing in the profile header length.
2030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile);
2032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (temp != profile_length)
2033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, name, temp,
20347a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "length does not match profile");
2035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
20369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   temp = (png_uint_32) (*(profile+8));
20379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (temp > 3 && (profile_length & 3))
20389b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return png_icc_profile_error(png_ptr, colorspace, name, profile_length,
20397a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "invalid length");
20409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */
2042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */
2043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      profile_length < 132+12*temp) /* truncated tag table */
2044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, name, temp,
20457a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "tag count too large");
2046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The 'intent' must be valid or we can't store it, ICC limits the intent to
2048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 16 bits.
2049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+64);
2051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (temp >= 0xffff) /* The ICC limit */
2052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, name, temp,
20537a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "invalid rendering intent");
2054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This is just a warning because the profile may be valid in future
2056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * versions.
2057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (temp >= PNG_sRGB_INTENT_LAST)
2059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (void)png_icc_profile_error(png_ptr, NULL, name, temp,
20607a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "intent outside defined range");
2061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* At this point the tag table can't be checked because it hasn't necessarily
2063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * been loaded; however, various header fields can be checked.  These checks
2064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * are for values permitted by the PNG spec in an ICC profile; the PNG spec
2065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * restricts the profiles that can be passed in an iCCP chunk (they must be
2066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * appropriate to processing PNG data!)
2067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Data checks (could be skipped).  These checks must be independent of the
2070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * version number; however, the version number doesn't accomodate changes in
2071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the header fields (just the known tags and the interpretation of the
2072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * data.)
2073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+36); /* signature 'ascp' */
2075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (temp != 0x61637370)
2076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_icc_profile_error(png_ptr, colorspace, name, temp,
20777a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "invalid signature");
2078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Currently the PCS illuminant/adopted white point (the computational
2080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * white point) are required to be D50,
2081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * however the profile contains a record of the illuminant so perhaps ICC
2082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * expects to be able to change this in the future (despite the rationale in
2083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the introduction for using a fixed PCS adopted white.)  Consequently the
2084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * following is just a warning.
2085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0)
2087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/,
20887a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          "PCS illuminant is not D50");
2089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The PNG spec requires this:
2091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * "If the iCCP chunk is present, the image samples conform to the colour
2092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * space represented by the embedded ICC profile as defined by the
2093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * International Color Consortium [ICC]. The colour space of the ICC profile
2094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * shall be an RGB colour space for colour images (PNG colour types 2, 3, and
2095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 6), or a greyscale colour space for greyscale images (PNG colour types 0
2096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * and 4)."
2097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
2098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * This checking code ensures the embedded profile (on either read or write)
2099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * conforms to the specification requirements.  Notice that an ICC 'gray'
2100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * color-space profile contains the information to transform the monochrome
2101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * data to XYZ or L*a*b (according to which PCS the profile uses) and this
2102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * should be used in preference to the standard libpng K channel replication
2103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * into R, G and B channels.
2104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
2105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Previously it was suggested that an RGB profile on grayscale data could be
2106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * handled.  However it it is clear that using an RGB profile in this context
2107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * must be an error - there is no specification of what it means.  Thus it is
2108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * almost certainly more correct to ignore the profile.
2109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+16); /* data colour space field */
2111b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   switch (temp)
2112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0x52474220: /* 'RGB ' */
21149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((color_type & PNG_COLOR_MASK_COLOR) == 0)
2115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            return png_icc_profile_error(png_ptr, colorspace, name, temp,
21167a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                "RGB color space not permitted on grayscale PNG");
2117b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0x47524159: /* 'GRAY' */
21209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
2121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            return png_icc_profile_error(png_ptr, colorspace, name, temp,
21227a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                "Gray color space not permitted on RGB PNG");
2123b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2124b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
2126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_icc_profile_error(png_ptr, colorspace, name, temp,
21277a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "invalid ICC profile color space");
2128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2129b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* It is up to the application to check that the profile class matches the
2131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * application requirements; the spec provides no guidance, but it's pretty
2132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer
2133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * ('prtr') or 'spac' (for generic color spaces).  Issue a warning in these
2134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * cases.  Issue an error for device link or abstract profiles - these don't
2135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * contain the records necessary to transform the color-space to anything
2136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * other than the target device (and not even that for an abstract profile).
2137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * Profiles of these classes may not be embedded in images.
2138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+12); /* profile/device class */
2140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   switch (temp)
2141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
21429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x73636e72: /* 'scnr' */
21439b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x6d6e7472: /* 'mntr' */
2144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0x70727472: /* 'prtr' */
2145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0x73706163: /* 'spac' */
2146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* All supported */
2147b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 0x61627374: /* 'abst' */
2150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* May not be embedded in an image */
2151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_icc_profile_error(png_ptr, colorspace, name, temp,
21527a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "invalid embedded Abstract ICC profile");
2153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
21549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x6c696e6b: /* 'link' */
21559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         /* DeviceLink profiles cannot be interpreted in a non-device specific
2156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * fashion, if an app uses the AToB0Tag in the profile the results are
2157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * undefined unless the result is sent to the intended device,
2158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * therefore a DeviceLink profile should not be found embedded in a
2159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * PNG.
2160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_icc_profile_error(png_ptr, colorspace, name, temp,
21627a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "unexpected DeviceLink ICC profile class");
2163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
21649b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x6e6d636c: /* 'nmcl' */
2165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* A NamedColor profile is also device specific, however it doesn't
21669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * contain an AToB0 tag that is open to misinterpretation.  Almost
2167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * certainly it will fail the tests below.
2168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         (void)png_icc_profile_error(png_ptr, NULL, name, temp,
21707a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "unexpected NamedColor ICC profile class");
2171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
2174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* To allow for future enhancements to the profile accept unrecognized
2175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * profile classes with a warning, these then hit the test below on the
2176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * tag content to ensure they are backward compatible with one of the
2177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * understood profiles.
2178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         (void)png_icc_profile_error(png_ptr, NULL, name, temp,
21807a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "unrecognized ICC profile class");
2181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* For any profile other than a device link one the PCS must be encoded
2185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * either in XYZ or Lab.
2186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   temp = png_get_uint_32(profile+20);
2188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   switch (temp)
2189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
21909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x58595a20: /* 'XYZ ' */
21919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      case 0x4c616220: /* 'Lab ' */
2192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:
2195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return png_icc_profile_error(png_ptr, colorspace, name, temp,
21967a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "unexpected ICC PCS encoding");
2197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
2200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2202b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
2203b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace,
22047a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_uint_32 profile_length,
22057a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_bytep profile /* header plus whole tag table */)
2206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 tag_count = png_get_uint_32(profile+128);
2208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 itag;
2209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_const_bytep tag = profile+132; /* The first tag */
2210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* First scan all the tags in the table and add bits to the icc_info value
2212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * (temporarily in 'tags').
2213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   for (itag=0; itag < tag_count; ++itag, tag += 12)
2215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_32 tag_id = png_get_uint_32(tag+0);
2217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */
2218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */
2219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The ICC specification does not exclude zero length tags, therefore the
2221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * start might actually be anywhere if there is no data, but this would be
2222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * a clear abuse of the intent of the standard so the start is checked for
2223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * being in range.  All defined tag types have an 8 byte header - a 4 byte
2224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * type signature then 0.
2225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
22263cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III
22273cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      /* This is a hard error; potentially it can cause read outside the
22283cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III       * profile.
22293cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III       */
22303cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      if (tag_start > profile_length || tag_length > profile_length - tag_start)
22313cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         return png_icc_profile_error(png_ptr, colorspace, name, tag_id,
22323cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III             "ICC profile tag outside profile");
22333cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III
2234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if ((tag_start & 3) != 0)
2235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
22363cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is
2237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * only a warning here because libpng does not care about the
2238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * alignment.
2239b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         (void)png_icc_profile_error(png_ptr, NULL, name, tag_id,
22417a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             "ICC profile tag start not a multiple of 4");
2242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1; /* success, maybe with warnings */
2246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_sRGB_SUPPORTED
22499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#if PNG_sRGB_PROFILE_CHECKS >= 0
2250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Information about the known ICC sRGB profiles */
2251b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic const struct
2252b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2253b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 adler, crc, length;
2254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 md5[4];
2255b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_byte    have_md5;
2256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_byte    is_broken;
2257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_16 intent;
2258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
2260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\
2261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      { adler, crc, length, md5, broke, intent },
2262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik} png_sRGB_checks[] =
2264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This data comes from contrib/tools/checksum-icc run on downloads of
2266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * all four ICC sRGB profiles from www.color.org.
2267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* adler32, crc32, MD5[4], intent, date, length, file-name */
2269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
22707a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0,
22717a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
2272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* ICC sRGB v2 perceptual no black-compensation: */
2274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
22757a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0,
22767a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
2277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,
22797a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0,
22807a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
2281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* ICC sRGB v4 perceptual */
2283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
22847a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0,
22857a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
2286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The following profiles have no known MD5 checksum. If there is a match
2288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * on the (empty) MD5 the other fields are used to attempt a match and
2289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * a warning is produced.  The first two of these profiles have a 'cprt' tag
2290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * which suggests that they were also made by Hewlett Packard.
2291b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2292b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,
22937a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0,
22947a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
2295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not
2297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * match the D50 PCS illuminant in the header (it is in fact the D65 values,
2298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * so the white point is recorded as the un-adapted value.)  The profiles
2299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * below only differ in one byte - the intent - and are basically the same as
2300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the previous profile except for the mediaWhitePointTag error and a missing
2301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * chromaticAdaptationTag.
2302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,
23047a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/,
23057a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual")
2306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d,
23087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/,
23097a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative")
2310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
2311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2312b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
2313b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
23147a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_bytep profile, uLong adler)
2315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The quick check is to verify just the MD5 signature and trust the
2317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * rest of the data.  Because the profile has already been verified for
2318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'
2319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * field too, so if the profile has been edited with an intent not defined
2320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * by sRGB (but maybe defined by a later ICC specification) the read of
2321b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the profile will fail at that point.
2322b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
23239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 length = 0;
2325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 intent = 0x10000; /* invalid */
2326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if PNG_sRGB_PROFILE_CHECKS > 1
2327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   uLong crc = 0; /* the value for 0 length data */
2328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
2329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int i;
2330b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
23319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_SET_OPTION_SUPPORTED
23329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */
23339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) ==
23349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               PNG_OPTION_ON)
23359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      return 0;
23369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
23379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
2338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)
2339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
2341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
2342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
2343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
2344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2345b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* This may be one of the old HP profiles without an MD5, in that
2346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * case we can only use the length and Adler32 (note that these
2347b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * are not used by default if there is an MD5!)
2348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2349b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#        if PNG_sRGB_PROFILE_CHECKS == 0
23509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            if (png_sRGB_checks[i].have_md5 != 0)
2351b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               return 1+png_sRGB_checks[i].is_broken;
2352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#        endif
2353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Profile is unsigned or more checks have been configured in. */
2355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (length == 0)
2356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
2357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            length = png_get_uint_32(profile);
2358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            intent = png_get_uint_32(profile+64);
2359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
2360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Length *and* intent must match */
23629b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (length == (png_uint_32) png_sRGB_checks[i].length &&
23639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            intent == (png_uint_32) png_sRGB_checks[i].intent)
2364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
2365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Now calculate the adler32 if not done already. */
2366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (adler == 0)
2367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
2368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               adler = adler32(0, NULL, 0);
2369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               adler = adler32(adler, profile, length);
2370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
2371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (adler == png_sRGB_checks[i].adler)
2373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
2374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* These basic checks suggest that the data has not been
2375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * modified, but if the check level is more than 1 perform
2376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * our own crc32 checksum on the data.
2377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
2378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#              if PNG_sRGB_PROFILE_CHECKS > 1
2379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (crc == 0)
2380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
2381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     crc = crc32(0, NULL, 0);
2382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     crc = crc32(crc, profile, length);
2383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
2384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  /* So this check must pass for the 'return' below to happen.
2386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                   */
2387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (crc == png_sRGB_checks[i].crc)
2388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#              endif
2389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
23909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  if (png_sRGB_checks[i].is_broken != 0)
2391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
2392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     /* These profiles are known to have bad data that may cause
2393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      * problems if they are used, therefore attempt to
2394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      * discourage their use, skip the 'have_md5' warning below,
2395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      * which is made irrelevant by this error.
2396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      */
2397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     png_chunk_report(png_ptr, "known incorrect sRGB profile",
23987a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                         PNG_CHUNK_ERROR);
2399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
2400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  /* Warn that this being done; this isn't even an error since
2402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                   * the profile is perfectly valid, but it would be nice if
2403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                   * people used the up-to-date ones.
2404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                   */
24059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                  else if (png_sRGB_checks[i].have_md5 == 0)
2406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
2407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     png_chunk_report(png_ptr,
24087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                         "out-of-date sRGB profile with no signature",
24097a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                         PNG_CHUNK_WARNING);
2410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
2411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  return 1+png_sRGB_checks[i].is_broken;
2413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
2414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
2415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2416b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# if PNG_sRGB_PROFILE_CHECKS > 0
2417b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         /* The signature matched, but the profile had been changed in some
2418b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * way.  This probably indicates a data error or uninformed hacking.
2419b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          * Fall through to "no match".
2420b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari          */
2421b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         png_chunk_report(png_ptr,
242206f1087a94f1e48298e89d77ccc51a0ced871958Matt Sarett             "Not recognizing known sRGB profile that has been edited",
2423b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari             PNG_CHUNK_WARNING);
2424b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari         break;
2425b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari# endif
24269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         }
2427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* no match */
2431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2433b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
2434b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_icc_set_sRGB(png_const_structrp png_ptr,
24357a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_colorspacerp colorspace, png_const_bytep profile, uLong adler)
2436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Is this profile one of the known ICC sRGB profiles?  If it is, just set
2438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the sRGB information.
2439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
24409b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0)
2441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (void)png_colorspace_set_sRGB(png_ptr, colorspace,
2442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         (int)/*already checked*/png_get_uint_32(profile+64));
2443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
24447a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */
24459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* sRGB */
2446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2447b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
2448b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace,
24497a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_const_charp name, png_uint_32 profile_length, png_const_bytep profile,
24507a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int color_type)
2451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
24529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0)
2453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
2454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
24557a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 &&
24569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       png_icc_check_header(png_ptr, colorspace, name, profile_length, profile,
24577a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis           color_type) != 0 &&
24589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
24597a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis           profile) != 0)
2460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
24617a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis#     if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0
2462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* If no sRGB support, don't try storing sRGB information */
2463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_icc_set_sRGB(png_ptr, colorspace, profile, 0);
2464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
2465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 1;
2466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Failure case */
2469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
2470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* iCCP */
2472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
2474b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
2475b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_colorspace_set_rgb_coefficients(png_structrp png_ptr)
2476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Set the rgb_to_gray coefficients from the colorspace. */
24789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_ptr->rgb_to_gray_coefficients_set == 0 &&
2479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
2480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* png_set_background has not been called, get the coefficients from the Y
2482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * values of the colorspace colorants.
2483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
2484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y;
2485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y;
2486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y;
2487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_fixed_point total = r+g+b;
2488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (total > 0 &&
2490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 &&
2491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 &&
2492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 &&
2493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         r+g+b <= 32769)
2494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* We allow 0 coefficients here.  r+g+b may be 32769 if two or
2496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * all of the coefficients were rounded up.  Handle this by
2497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * reducing the *largest* coefficient by 1; this matches the
2498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * approach used for the default coefficients in pngrtran.c
2499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         int add = 0;
2501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (r+g+b > 32768)
2503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            add = -1;
2504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else if (r+g+b < 32768)
2505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            add = 1;
2506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (add != 0)
2508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
2509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (g >= r && g >= b)
2510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               g += add;
2511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            else if (r >= g && r >= b)
2512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               r += add;
2513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            else
2514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               b += add;
2515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
2516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Check for an internal error. */
2518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (r+g+b != 32768)
2519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_error(png_ptr,
25207a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis                "internal error handling cHRM coefficients");
2521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
2523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
2524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;
2525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
2526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
2527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* This is a png_error at present even though it could be ignored -
2530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * it should never happen, but it is important that if it does, the
2531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * bug is fixed.
2532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
2533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
2534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_error(png_ptr, "internal error handling cHRM->XYZ");
2535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2536b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
25379b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ_RGB_TO_GRAY */
2538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2539b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* COLORSPACE */
2540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2541f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath#ifdef __GNUC__
2542f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath/* This exists solely to work round a warning from GNU C. */
2543f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamathstatic int /* PRIVATE */
2544f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamathpng_gt(size_t a, size_t b)
2545f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath{
25467a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   return a > b;
2547f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath}
2548f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath#else
2549f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath#   define png_gt(a,b) ((a) > (b))
2550f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath#endif
2551f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath
2552b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
2553b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_check_IHDR(png_const_structrp png_ptr,
25547a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_uint_32 width, png_uint_32 height, int bit_depth,
25557a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int color_type, int interlace_type, int compression_type,
25567a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    int filter_type)
2557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int error = 0;
25595f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
25605f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   /* Check for width and height valid values */
25615f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   if (width == 0)
25625f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
2563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Image width is zero in IHDR");
2564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
25669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
25679b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (width > PNG_UINT_31_MAX)
2568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2569f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath      png_warning(png_ptr, "Invalid image width in IHDR");
2570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
25733cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III   if (png_gt(((width + 7) & (~7U)),
25749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       ((PNG_SIZE_MAX
25759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett           - 48        /* big_row_buf hack */
25769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett           - 1)        /* filter byte */
25779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett           / 8)        /* 8-byte RGBA pixels */
25789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett           - 1))       /* extra max_pixel_depth pad */
2579f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath   {
2580f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath      /* The size of the row must be within the limits of this architecture.
2581f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * Because the read code can perform arbitrary transformations the
2582f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * maximum size is checked here.  Because the code in png_read_start_row
2583f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * adds extra space "for safety's sake" in several places a conservative
2584f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * limit is used here.
2585f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       *
2586f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * NOTE: it would be far better to check the size that is actually used,
2587f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * but the effect in the real world is minor and the changes are more
2588f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * extensive, therefore much more dangerous and much more difficult to
2589f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       * write in a way that avoids compiler warnings.
2590f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath       */
25919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_warning(png_ptr, "Image width is too large for this architecture");
25929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      error = 1;
2593f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath   }
2594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
25959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_SET_USER_LIMITS_SUPPORTED
25969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (width > png_ptr->user_width_max)
25979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#else
25989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (width > PNG_USER_WIDTH_MAX)
25999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
2600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Image width exceeds user limit in IHDR");
2602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2605f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath   if (height == 0)
2606f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath   {
2607f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath      png_warning(png_ptr, "Image height is zero in IHDR");
2608f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath      error = 1;
2609f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath   }
2610f4435dfcdb5733f9c340492cc7fcac88a13f6ebdNarayan Kamath
26119b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (height > PNG_UINT_31_MAX)
2612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
26139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_warning(png_ptr, "Invalid image height in IHDR");
2614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
26179b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_SET_USER_LIMITS_SUPPORTED
26189b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (height > png_ptr->user_height_max)
26199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#else
26209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (height > PNG_USER_HEIGHT_MAX)
26219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
2622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
26239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_warning(png_ptr, "Image height exceeds user limit in IHDR");
2624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Check other values */
2628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
2629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       bit_depth != 8 && bit_depth != 16)
2630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Invalid bit depth in IHDR");
2632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (color_type < 0 || color_type == 1 ||
2636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       color_type == 5 || color_type > 6)
2637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Invalid color type in IHDR");
2639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
2643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       ((color_type == PNG_COLOR_TYPE_RGB ||
2644b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
2645b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
2646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR");
2648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (interlace_type >= PNG_INTERLACE_LAST)
2652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Unknown interlace method in IHDR");
2654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
2658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Unknown compression method in IHDR");
2660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
26639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_MNG_FEATURES_SUPPORTED
2664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Accept filter_method 64 (intrapixel differencing) only if
2665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
2666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 2. Libpng did not read a PNG signature (this filter_method is only
2667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    used in PNG datastreams that are embedded in MNG datastreams) and
2668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 3. The application called png_permit_mng_features with a mask that
2669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *    included PNG_FLAG_MNG_FILTER_64 and
2670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 4. The filter_method is 64 and
2671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 5. The color_type is RGB or RGBA
2672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
26739b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 &&
26749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett       png_ptr->mng_features_permitted != 0)
2675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
2676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (filter_type != PNG_FILTER_TYPE_BASE)
2678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
26799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
2680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
2681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) &&
2682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          (color_type == PNG_COLOR_TYPE_RGB ||
2683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
2684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_warning(png_ptr, "Unknown filter method in IHDR");
2686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         error = 1;
2687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
26899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0)
2690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_warning(png_ptr, "Invalid filter method in IHDR");
2692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         error = 1;
2693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
26969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#else
2697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (filter_type != PNG_FILTER_TYPE_BASE)
2698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_warning(png_ptr, "Unknown filter method in IHDR");
2700b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      error = 1;
2701b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
27029b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
2703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (error == 1)
2705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_error(png_ptr, "Invalid IHDR data");
2706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED)
2709b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* ASCII to fp functions */
2710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Check an ASCII formated floating point value, see the more detailed
2711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * comments in pngpriv.h
2712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
2713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following is used internally to preserve the sticky flags */
2714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define png_fp_add(state, flags) ((state) |= (flags))
2715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY))
2716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2717b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
2718b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_check_fp_number(png_const_charp string, png_size_t size, int *statep,
27197a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    png_size_tp whereami)
2720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int state = *statep;
2722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_size_t i = *whereami;
2723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   while (i < size)
2725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int type;
2727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* First find the type of the next character */
2728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      switch (string[i])
2729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 43:  type = PNG_FP_SAW_SIGN;                   break;
2731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 45:  type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break;
2732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 46:  type = PNG_FP_SAW_DOT;                    break;
2733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 48:  type = PNG_FP_SAW_DIGIT;                  break;
2734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 49: case 50: case 51: case 52:
2735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 53: case 54: case 55: case 56:
2736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 57:  type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break;
2737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 69:
2738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case 101: type = PNG_FP_SAW_E;                      break;
2739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default:  goto PNG_FP_End;
2740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Now deal with this type according to the current
2743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * state, the type is arranged to not overlap the
2744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * bits of the PNG_FP_STATE.
2745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
2746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY))
2747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_INTEGER + PNG_FP_SAW_SIGN:
27499b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((state & PNG_FP_SAW_ANY) != 0)
2750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            goto PNG_FP_End; /* not a part of the number */
2751b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_add(state, type);
2753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_INTEGER + PNG_FP_SAW_DOT:
2756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Ok as trailer, ok as lead of fraction. */
27579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */
2758b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            goto PNG_FP_End;
2759b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
27609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */
2761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_fp_add(state, type);
2762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
2764b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_fp_set(state, PNG_FP_FRACTION | type);
2765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2767b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2768b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT:
27699b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */
2770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT);
2771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_add(state, type | PNG_FP_WAS_VALID);
2773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_INTEGER + PNG_FP_SAW_E:
2777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if ((state & PNG_FP_SAW_DIGIT) == 0)
2778b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            goto PNG_FP_End;
2779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_set(state, PNG_FP_EXPONENT);
2781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN:
2785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         goto PNG_FP_End; ** no sign in fraction */
2786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT:
2788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         goto PNG_FP_End; ** Because SAW_DOT is always set */
2789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT:
2791b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_add(state, type | PNG_FP_WAS_VALID);
2792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2793b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2794b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_FRACTION + PNG_FP_SAW_E:
2795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* This is correct because the trailing '.' on an
2796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * integer is handled above - so we can only get here
2797b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * with the sequence ".E" (with no preceding digits).
2798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2799b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if ((state & PNG_FP_SAW_DIGIT) == 0)
2800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            goto PNG_FP_End;
2801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_set(state, PNG_FP_EXPONENT);
2803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN:
28079b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if ((state & PNG_FP_SAW_ANY) != 0)
2808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            goto PNG_FP_End; /* not a part of the number */
2809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_add(state, PNG_FP_SAW_SIGN);
2811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT:
2815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         goto PNG_FP_End; */
2816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT:
2818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID);
2819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         break;
2821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E:
2823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         goto PNG_FP_End; */
2824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      default: goto PNG_FP_End; /* I.e. break 2 */
2826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The character seems ok, continue. */
2829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      ++i;
2830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2831b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2832b50c217251b086440efcdb273c22f86a06c80cbaChris CraikPNG_FP_End:
2833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Here at the end, update the state and return the correct
2834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * return code.
2835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   *statep = state;
2837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   *whereami = i;
2838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (state & PNG_FP_SAW_DIGIT) != 0;
2840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2841b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2842b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The same but for a complete string. */
2844b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint
2845b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_check_fp_string(png_const_charp string, png_size_t size)
2846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2847b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int        state=0;
2848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_size_t char_index=0;
2849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
28509b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_check_fp_number(string, size, &state, &char_index) != 0 &&
2851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (char_index == size || string[char_index] == 0))
2852b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return state /* must be non-zero - see above */;
2853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* i.e. fail */
2855b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
28569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* pCAL || sCAL */
2857b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_sCAL_SUPPORTED
2859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_FLOATING_POINT_SUPPORTED
2860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Utility used below - a simple accurate power of ten from an integral
2861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * exponent.
2862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
2863b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic double
2864b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_pow10(int power)
2865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2866b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   int recip = 0;
2867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   double d = 1;
2868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2869b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Handle negative exponent with a reciprocal at the end because
2870b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 10 is exact whereas .1 is inexact in base 2
2871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (power < 0)
2873b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (power < DBL_MIN_10_EXP) return 0;
28753cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      recip = 1; power = -power;
2876b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2877b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2878b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (power > 0)
2879b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2880b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Decompose power bitwise. */
2881b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      double mult = 10;
2882b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      do
2883b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2884b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (power & 1) d *= mult;
2885b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         mult *= mult;
2886b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         power >>= 1;
2887b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2888b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      while (power > 0);
2889b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
28909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (recip != 0) d = 1/d;
2891b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
2892b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* else power is 0 and d is 1 */
2893b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2894b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return d;
2895b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
2896b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2897b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Function to format a floating point value in ASCII with a given
2898b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * precision.
2899b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
29003cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#if GCC_STRICT_OVERFLOW
29013cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic push
29023cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III/* The problem arises below with exp_b10, which can never overflow because it
29033cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * comes, originally, from frexp and is therefore limited to a range which is
29043cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)).
29053cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III */
29063cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic warning "-Wstrict-overflow=2"
29073cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GCC_STRICT_OVERFLOW */
2908b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
2909b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size,
2910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    double fp, unsigned int precision)
2911b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
2912b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* We use standard functions from math.h, but not printf because
2913b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * that would require stdio.  The caller must supply a buffer of
2914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * sufficient size or we will png_error.  The tests on size and
2915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the space in ascii[] consumed are indicated below.
2916b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
2917b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (precision < 1)
2918b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      precision = DBL_DIG;
2919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Enforce the limit of the implementation precision too. */
2921b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (precision > DBL_DIG+1)
2922b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      precision = DBL_DIG+1;
2923b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2924b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Basic sanity checks */
2925b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (size >= precision+5) /* See the requirements below. */
2926b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
2927b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (fp < 0)
2928b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
2929b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         fp = -fp;
2930b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii++ = 45; /* '-'  PLUS 1 TOTAL 1 */
2931b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         --size;
2932b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
2933b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2934b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (fp >= DBL_MIN && fp <= DBL_MAX)
2935b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
29369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         int exp_b10;   /* A base 10 exponent */
2937b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         double base;   /* 10^exp_b10 */
2938b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2939b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* First extract a base 10 exponent of the number,
2940b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * the calculation below rounds down when converting
2941b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * from base 2 to base 10 (multiply by log10(2) -
2942b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to
2943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * be increased.  Note that the arithmetic shift
2944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * performs a floor() unlike C arithmetic - using a
2945b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * C multiply would break the following for negative
2946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * exponents.
2947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         (void)frexp(fp, &exp_b10); /* exponent to base 2 */
2949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */
2951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2952b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Avoid underflow here. */
2953b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         base = png_pow10(exp_b10); /* May underflow */
2954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         while (base < DBL_MIN || base < fp)
2956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
2957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* And this may overflow. */
2958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            double test = png_pow10(exp_b10+1);
2959b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (test <= DBL_MAX)
29613cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III            {
29623cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               ++exp_b10; base = test;
29633cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III            }
2964b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2965b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            else
2966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               break;
2967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
2968b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Normalize fp and correct exp_b10, after this fp is in the
2970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * range [.1,1) and exp_b10 is both the exponent and the digit
2971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * *before* which the decimal point should be inserted
2972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * (starting with 0 for the first digit).  Note that this
2973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * works even if 10^exp_b10 is out of range because of the
2974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * test on DBL_MAX above.
2975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         fp /= base;
29773cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         while (fp >= 1)
29783cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         {
29793cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III            fp /= 10; ++exp_b10;
29803cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         }
2981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Because of the code above fp may, at this point, be
2983b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * less than .1, this is ok because the code below can
2984b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * handle the leading zeros this generates, so no attempt
2985b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * is made to correct that here.
2986b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
2987b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2988b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
29899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            unsigned int czero, clead, cdigits;
2990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            char exponent[10];
2991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
2992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Allow up to two leading zeros - this will not lengthen
2993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * the number compared to using E-n.
2994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
2995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */
2996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
29973cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */
2998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               exp_b10 = 0;      /* Dot added below before first output. */
2999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            else
3001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               czero = 0;    /* No zeros to add */
3002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Generate the digit list, stripping trailing zeros and
3004b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * inserting a '.' before a digit if the exponent is 0.
3005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            clead = czero; /* Count of leading zeros */
3007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            cdigits = 0;   /* Count of digits in list. */
3008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            do
3010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               double d;
3012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               fp *= 10;
3014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* Use modf here, not floor and subtract, so that
3015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * the separation is done in one step.  At the end
3016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * of the loop don't break the number into parts so
3017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * that the final digit is rounded.
3018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
30199b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (cdigits+czero+1 < precision+clead)
3020b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  fp = modf(fp, &d);
3021b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3022b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               else
3023b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
3024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  d = floor(fp + .5);
3025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3026b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (d > 9)
3027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
3028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     /* Rounding up to 10, handle that here. */
3029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     if (czero > 0)
3030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     {
30313cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                        --czero; d = 1;
3032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        if (cdigits == 0) --clead;
3033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     }
3034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     else
3035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     {
3036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        while (cdigits > 0 && d > 9)
3037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        {
3038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           int ch = *--ascii;
3039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           if (exp_b10 != (-1))
3041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              ++exp_b10;
3042b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           else if (ch == 46)
3044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           {
30453cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                              ch = *--ascii; ++size;
3046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              /* Advance exp_b10 to '1', so that the
3047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               * decimal point happens after the
3048b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               * previous digit.
3049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               */
3050b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              exp_b10 = 1;
3051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           }
3052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           --cdigits;
3054b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           d = ch - 47;  /* I.e. 1+(ch-48) */
3055b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        }
3056b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        /* Did we reach the beginning? If so adjust the
3058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                         * exponent but take into account the leading
3059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                         * decimal point.
3060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                         */
3061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        if (d > 9)  /* cdigits == 0 */
3062b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        {
3063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           if (exp_b10 == (-1))
3064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           {
3065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              /* Leading decimal point (plus zeros?), if
3066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               * we lose the decimal point here it must
3067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               * be reentered below.
3068b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               */
3069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              int ch = *--ascii;
3070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              if (ch == 46)
30723cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                              {
30733cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                                 ++size; exp_b10 = 1;
30743cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                              }
3075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              /* Else lost a leading zero, so 'exp_b10' is
3077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               * still ok at (-1)
3078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                               */
3079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           }
3080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           else
3081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                              ++exp_b10;
3082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           /* In all cases we output a '1' */
3084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           d = 1;
3085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        }
3086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     }
3087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
3088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  fp = 0; /* Guarantees termination below. */
3089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               if (d == 0)
3092b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
3093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  ++czero;
3094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (cdigits == 0) ++clead;
3095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               else
3097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
3098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  /* Included embedded zeros in the digit count. */
3099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  cdigits += czero - clead;
3100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  clead = 0;
3101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  while (czero > 0)
3103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
3104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     /* exp_b10 == (-1) means we just output the decimal
3105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      * place - after the DP don't adjust 'exp_b10' any
3106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      * more!
3107b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                      */
3108b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     if (exp_b10 != (-1))
3109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     {
31103cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                        if (exp_b10 == 0)
31113cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                        {
31123cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                           *ascii++ = 46; --size;
31133cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                        }
3114b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        /* PLUS 1: TOTAL 4 */
3115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                        --exp_b10;
3116b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     }
31173cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                     *ascii++ = 48; --czero;
3118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
3119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3120b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (exp_b10 != (-1))
3121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  {
31229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                     if (exp_b10 == 0)
31233cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                     {
31243cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                        *ascii++ = 46; --size; /* counted above */
31253cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                     }
31269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett
3127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     --exp_b10;
3128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  }
31293cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                  *ascii++ = (char)(48 + (int)d); ++cdigits;
3130b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3131b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
31329b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            while (cdigits+czero < precision+clead && fp > DBL_MIN);
3133b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3134b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* The total output count (max) is now 4+precision */
3135b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Check for an exponent, if we don't need one we are
3137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * done and just need to terminate the string.  At
31383cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III             * this point exp_b10==(-1) is effectively a flag - it got
31399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett             * to '-1' because of the decrement after outputting
3140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * the decimal point above (the exponent required is
3141b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * *not* -1!)
3142b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (exp_b10 >= (-1) && exp_b10 <= 2)
3144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* The following only happens if we didn't output the
3146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * leading zeros above for negative exponent, so this
31479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                * doesn't add to the digit requirement.  Note that the
3148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * two zeros here can only be output if the two leading
3149b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * zeros were *not* output, so this doesn't increase
3150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * the output count.
3151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
31523cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               while (exp_b10-- > 0) *ascii++ = 48;
3153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               *ascii = 0;
3155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* Total buffer requirement (including the '\0') is
3157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * 5+precision - see check at the start.
3158b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
3159b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               return;
3160b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Here if an exponent is required, adjust size for
3163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * the digits we output but did not count.  The total
3164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * digit output here so far is at most 1+precision - no
3165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * decimal point and no leading or trailing zeros have
3166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * been output.
3167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            size -= cdigits;
3169b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
31703cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III            *ascii++ = 69; --size;    /* 'E': PLUS 1 TOTAL 2+precision */
3171b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* The following use of an unsigned temporary avoids ambiguities in
3173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * the signed arithmetic on exp_b10 and permits GCC at least to do
3174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * better optimization.
3175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               unsigned int uexp_b10;
3178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               if (exp_b10 < 0)
3180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
31813cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                  *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */
31823cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                  uexp_b10 = 0U-exp_b10;
3183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               else
31863cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                  uexp_b10 = 0U+exp_b10;
3187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               cdigits = 0;
3189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               while (uexp_b10 > 0)
3191b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
3192b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  exponent[cdigits++] = (char)(48 + uexp_b10 % 10);
3193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  uexp_b10 /= 10;
3194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3195b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Need another size check here for the exponent digits, so
3198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * this need not be considered above.
3199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
32009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            if (size > cdigits)
3201b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3202b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               while (cdigits > 0) *ascii++ = exponent[--cdigits];
3203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3204b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               *ascii = 0;
3205b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3206b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               return;
3207b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3208b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
3209b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
3210b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else if (!(fp >= DBL_MIN))
3211b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3212b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii++ = 48; /* '0' */
3213b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii = 0;
3214b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return;
3215b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
3216b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
3217b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3218b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii++ = 105; /* 'i' */
3219b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii++ = 110; /* 'n' */
3220b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii++ = 102; /* 'f' */
3221b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii = 0;
3222b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return;
3223b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
3224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
3225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Here on buffer too small. */
3227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_error(png_ptr, "ASCII conversion buffer too small");
3228b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
32293cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#if GCC_STRICT_OVERFLOW
32303cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic pop
32313cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GCC_STRICT_OVERFLOW */
3232b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3233b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif /* FLOATING_POINT */
3234b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3235b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_FIXED_POINT_SUPPORTED
3236b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Function to format a fixed point value in ASCII.
3237b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3238b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
3239b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,
3240b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_size_t size, png_fixed_point fp)
3241b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3242b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Require space for 10 decimal digits, a decimal point, a minus sign and a
3243b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * trailing \0, 13 characters:
3244b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3245b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (size > 12)
3246b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
3247b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_32 num;
3248b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3249b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Avoid overflow here on the minimum integer. */
3250b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (fp < 0)
32513cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      {
32523cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         *ascii++ = 45; num = (png_uint_32)(-fp);
32533cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      }
3254b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
32553cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III         num = (png_uint_32)fp;
3256b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3257b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (num <= 0x80000000) /* else overflowed */
3258b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3259b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         unsigned int ndigits = 0, first = 16 /* flag value */;
3260b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         char digits[10];
3261b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3262b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         while (num)
3263b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
3264b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Split the low digit off num: */
3265b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            unsigned int tmp = num/10;
3266b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            num -= tmp*10;
3267b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            digits[ndigits++] = (char)(48 + num);
3268b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Record the first non-zero digit, note that this is a number
3269b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * starting at 1, it's not actually the array index.
3270b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3271b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (first == 16 && num > 0)
3272b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               first = ndigits;
3273b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            num = tmp;
3274b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
3275b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3276b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (ndigits > 0)
3277b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
3278b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            while (ndigits > 5) *ascii++ = digits[--ndigits];
3279b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* The remaining digits are fractional digits, ndigits is '5' or
3280b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * smaller at this point.  It is certainly not zero.  Check for a
3281b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * non-zero fractional digit:
3282b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3283b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (first <= 5)
3284b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3285b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               unsigned int i;
3286b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               *ascii++ = 46; /* decimal point */
3287b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* ndigits may be <5 for small numbers, output leading zeros
3288b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                * then ndigits digits to first:
3289b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                */
3290b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               i = 5;
32913cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               while (ndigits < i)
32923cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               {
32933cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III                  *ascii++ = 48; --i;
32943cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III               }
3295b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               while (ndigits >= first) *ascii++ = digits[--ndigits];
3296b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* Don't output the trailing zeros! */
3297b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3298b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
3299b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
3300b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            *ascii++ = 48;
3301b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3302b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* And null terminate the string: */
3303b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *ascii = 0;
3304b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return;
3305b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
3306b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
3307b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3308b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Here on buffer too small. */
3309b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_error(png_ptr, "ASCII conversion buffer too small");
3310b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3311b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#   endif /* FIXED_POINT */
33129b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* SCAL */
3313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
3315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
3316b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
3317b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \
3318b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \
3319b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   (defined(PNG_sCAL_SUPPORTED) && \
3320b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED))
3321b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_fixed_point
3322b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
3323b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3324b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   double r = floor(100000 * fp + .5);
3325b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3326b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (r > 2147483647. || r < -2147483648.)
3327b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_fixed_error(png_ptr, text);
3328b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3329b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  ifndef PNG_ERROR_TEXT_SUPPORTED
33309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   PNG_UNUSED(text)
3331b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#  endif
3332b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari
3333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (png_fixed_point)r;
3334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3335b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3337b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\
3338b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
3339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* muldiv functions */
3340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This API takes signed arguments and rounds the result to the nearest
3341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * integer (or, for a fixed point number - the standard argument - to
3342b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the nearest .00001).  Overflow and divide by zero are signalled in
3343b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the result, a boolean - true on success, false on overflow.
3344b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
33453cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#if GCC_STRICT_OVERFLOW /* from above */
33463cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III/* It is not obvious which comparison below gets optimized in such a way that
33473cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * signed overflow would change the result; looking through the code does not
33483cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * reveal any tests which have the form GCC complains about, so presumably the
33493cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * optimizer is moving an add or subtract into the 'if' somewhere.
33503cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III */
33513cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic push
33523cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic warning "-Wstrict-overflow=2"
33533cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GCC_STRICT_OVERFLOW */
3354b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint
3355b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
3356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_int_32 divisor)
3357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Return a * times / divisor, rounded. */
3359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (divisor != 0)
3360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
3361b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (a == 0 || times == 0)
3362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3363b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         *res = 0;
3364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return 1;
3365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
3366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
3367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
3368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
3369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         double r = a;
3370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         r *= times;
3371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         r /= divisor;
3372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         r = floor(r+.5);
3373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3374b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* A png_fixed_point is a 32-bit integer. */
3375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (r <= 2147483647. && r >= -2147483648.)
3376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
3377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            *res = (png_fixed_point)r;
3378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            return 1;
3379b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
3380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else
3381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         int negative = 0;
3382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_uint_32 A, T, D;
3383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_uint_32 s16, s32, s00;
3384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (a < 0)
3386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            negative = 1, A = -a;
3387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
3388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            A = a;
3389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (times < 0)
3391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            negative = !negative, T = -times;
3392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
3393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            T = times;
3394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (divisor < 0)
3396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            negative = !negative, D = -divisor;
3397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         else
3398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            D = divisor;
3399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Following can't overflow because the arguments only
3401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * have 31 bits each, however the result may be 32 bits.
3402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
3403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         s16 = (A >> 16) * (T & 0xffff) +
3404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                           (A & 0xffff) * (T >> 16);
3405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Can't overflow because the a*times bit is only 30
3406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * bits at most.
3407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
3408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         s32 = (A >> 16) * (T >> 16) + (s16 >> 16);
3409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         s00 = (A & 0xffff) * (T & 0xffff);
3410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         s16 = (s16 & 0xffff) << 16;
3412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         s00 += s16;
3413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3414b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (s00 < s16)
3415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            ++s32; /* carry */
3416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (s32 < D) /* else overflow */
3418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
3419b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* s32.s00 is now the 64-bit product, do a standard
3420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * division, we know that s32 < D, so the maximum
3421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             * required shift is 31.
3422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik             */
3423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            int bitshift = 32;
3424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_fixed_point result = 0; /* NOTE: signed */
3425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            while (--bitshift >= 0)
3427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               png_uint_32 d32, d00;
3429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               if (bitshift > 0)
3431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  d32 = D >> (32-bitshift), d00 = D << bitshift;
3432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               else
3434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  d32 = 0, d00 = D;
3435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               if (s32 > d32)
3437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               {
3438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (s00 < d00) --s32; /* carry */
3439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  s32 -= d32, s00 -= d00, result += 1<<bitshift;
3440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               }
3441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               else
3443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  if (s32 == d32 && s00 >= d00)
3444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                     s32 = 0, s00 -= d00, result += 1<<bitshift;
3445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Handle the rounding. */
3448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            if (s00 >= (D >> 1))
3449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               ++result;
3450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
34519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            if (negative != 0)
3452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               result = -result;
3453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            /* Check for overflow. */
34559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            if ((negative != 0 && result <= 0) ||
34569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                (negative == 0 && result >= 0))
3457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            {
3458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               *res = result;
3459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               return 1;
3460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            }
3461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
3462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
34645f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
34655f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
3466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
3467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
34683cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#if GCC_STRICT_OVERFLOW
34693cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#pragma GCC diagnostic pop
34703cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III#endif /* GCC_STRICT_OVERFLOW */
3471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_GAMMA || INCH_CONVERSIONS */
3472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
3474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The following is for when the caller doesn't much care about the
3475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * result.
3476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3477b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_fixed_point
3478b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times,
3479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_int_32 divisor)
3480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point result;
3482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
34839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&result, a, times, divisor) != 0)
3484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return result;
3485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_warning(png_ptr, "fixed point overflow ignored");
3487b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
3488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */
3492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
3493b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_fixed_point
3494b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_reciprocal(png_fixed_point a)
3495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
3497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   double r = floor(1E10/a+.5);
3498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (r <= 2147483647. && r >= -2147483648.)
3500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return (png_fixed_point)r;
3501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else
3502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point res;
3503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
35049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&res, 100000, 100000, a) != 0)
3505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return res;
3506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* error/overflow */
3509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This is the shared test on whether a gamma value is 'significant' - whether
3512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * it is worth doing gamma correction.
3513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3514b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
3515b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_gamma_significant(png_fixed_point gamma_val)
3516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED ||
3518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
3519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GAMMA_SUPPORTED
35239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_16BIT_SUPPORTED
3524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* A local convenience routine. */
3525b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_fixed_point
3526b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_product2(png_fixed_point a, png_fixed_point b)
3527b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3528b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The required result is 1/a * 1/b; the following preserves accuracy. */
35299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
3530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   double r = a * 1E-5;
3531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   r *= b;
3532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   r = floor(r+.5);
3533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (r <= 2147483647. && r >= -2147483648.)
3535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return (png_fixed_point)r;
35369b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#else
3537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point res;
3538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
35399b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_muldiv(&res, a, b, 100000) != 0)
3540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return res;
35419b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
3542b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3543b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* overflow */
3544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
35459b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* 16BIT */
3546b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The inverse of the above. */
3548b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_fixed_point
3549b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_reciprocal2(png_fixed_point a, png_fixed_point b)
3550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The required result is 1/a * 1/b; the following preserves accuracy. */
3552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
35539b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (a != 0 && b != 0)
35549b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   {
35559b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      double r = 1E15/a;
35569b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      r /= b;
35579b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      r = floor(r+.5);
3558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
35599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (r <= 2147483647. && r >= -2147483648.)
35609b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         return (png_fixed_point)r;
35619b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   }
3562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#else
3563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* This may overflow because the range of png_fixed_point isn't symmetric,
3564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * but this API is only used for the product of file and screen gamma so it
3565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * doesn't matter that the smallest number it can produce is 1/21474, not
3566b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 1/100000
3567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_fixed_point res = png_product2(a, b);
3569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (res != 0)
3571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_reciprocal(res);
3572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0; /* overflow */
3575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_GAMMA */
3577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */
3579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED
3580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Fixed point gamma.
3581b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3582b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The code to calculate the tables used below can be found in the shell script
3583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * contrib/tools/intgamma.sh
3584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * To calculate gamma this code implements fast log() and exp() calls using only
3586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * fixed point arithmetic.  This code has sufficient precision for either 8-bit
3587b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * or 16-bit sample values.
3588b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The tables used here were calculated using simple 'bc' programs, but C double
3590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * precision floating point arithmetic would work fine.
3591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8-bit log table
3593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *   This is a table of -log(value/255)/log(2) for 'value' in the range 128 to
3594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *   255, so it's the base 2 logarithm of a normalized 8-bit floating point
3595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *   mantissa.  The numbers are 32-bit fractions.
3596b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3597b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic const png_uint_32
3598b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_8bit_l2[128] =
3599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3600b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U,
3601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U,
3602b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U,
3603b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U,
3604b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U,
3605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U,
3606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U,
3607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U,
3608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U,
3609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U,
3610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U,
3611b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U,
3612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U,
3613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U,
3614b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U,
3615b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U,
3616b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U,
3617b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U,
3618b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U,
3619b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U,
3620b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U,
3621b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   24347096U, 0U
3622b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3623b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if 0
3624b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* The following are the values for 16-bit tables - these work fine for the
3625b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 8-bit conversions but produce very slightly larger errors in the 16-bit
3626b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * log (about 1.2 as opposed to 0.7 absolute error in the final value).  To
3627b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * use these all the shifts below must be adjusted appropriately.
3628b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3629b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054,
3630b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803,
3631b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068,
3632b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782,
3633b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887,
3634b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339,
3635b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098,
3636b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132,
3637b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415,
3638b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523,
3639b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495,
3640b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1119, 744, 372
3641b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
3642b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
3643b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3644b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_int_32
3645b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_log8bit(unsigned int x)
3646b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3647b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int lg2 = 0;
3648b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log,
3649b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * because the log is actually negate that means adding 1.  The final
3650b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * returned value thus has the range 0 (for 255 input) to 7.994 (for 1
3651b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * input), return -1 for the overflow (log 0) case, - so the result is
3652b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * always at most 19 bits.
3653b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3654b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x &= 0xff) == 0)
3655b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return -1;
3656b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3657b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0xf0) == 0)
3658b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2  = 4, x <<= 4;
3659b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3660b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0xc0) == 0)
3661b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += 2, x <<= 2;
3662b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3663b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0x80) == 0)
3664b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += 1, x <<= 1;
3665b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3666b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* result is at most 19 bits, so this cast is safe: */
3667b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16));
3668b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3669b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3670b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The above gives exact (to 16 binary places) log2 values for 8-bit images,
3671b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * for 16-bit images we use the most significant 8 bits of the 16-bit value to
3672b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * get an approximation then multiply the approximation by a correction factor
3673b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * determined by the remaining up to 8 bits.  This requires an additional step
3674b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * in the 16-bit case.
3675b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3676b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * We want log2(value/65535), we have log2(v'/255), where:
3677b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3678b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *    value = v' * 256 + v''
3679b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *          = v' * f
3680b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3681b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128
3682b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less
3683b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * than 258.  The final factor also needs to correct for the fact that our 8-bit
3684b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * value is scaled by 255, whereas the 16-bit values must be scaled by 65535.
3685b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3686b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * This gives a final formula using a calculated value 'x' which is value/v' and
3687b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * scaling by 65536 to match the above table:
3688b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3689b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *   log2(x/257) * 65536
3690b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3691b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Since these numbers are so close to '1' we can use simple linear
3692b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * interpolation between the two end values 256/257 (result -368.61) and 258/257
3693b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * (result 367.179).  The values used below are scaled by a further 64 to give
3694b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 16-bit precision in the interpolation:
3695b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3696b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Start (256): -23591
3697b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * Zero  (257):      0
3698b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * End   (258):  23499
3699b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
37009b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_16BIT_SUPPORTED
3701b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_int_32
3702b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_log16bit(png_uint_32 x)
3703b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3704b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int lg2 = 0;
3705b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3706b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* As above, but now the input has 16 bits. */
3707b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x &= 0xffff) == 0)
3708b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return -1;
37095f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
3710b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0xff00) == 0)
3711b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2  = 8, x <<= 8;
3712b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3713b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0xf000) == 0)
3714b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += 4, x <<= 4;
3715b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3716b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0xc000) == 0)
3717b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += 2, x <<= 2;
3718b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3719b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if ((x & 0x8000) == 0)
3720b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += 1, x <<= 1;
3721b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3722b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional
3723b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * value.
3724b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3725b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   lg2 <<= 28;
3726b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4;
3727b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3728b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Now we need to interpolate the factor, this requires a division by the top
3729b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 8 bits.  Do this with maximum precision.
3730b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3731b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   x = ((x << 16) + (x >> 9)) / (x >> 8);
3732b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3733b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24,
3734b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly
3735b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 16 bits to interpolate to get the low bits of the result.  Round the
3736b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * answer.  Note that the end point values are scaled by 64 to retain overall
3737b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust
3738b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the overall scaling by 6-12.  Round at every step.
3739b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3740b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   x -= 1U << 24;
3741b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3742b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (x <= 65536U) /* <= '257' */
3743b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12);
3744b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3745b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
3746b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12);
3747b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3748b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Safe, because the result can't have more than 20 bits: */
3749b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (png_int_32)((lg2 + 2048) >> 12);
3750b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
37519b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* 16BIT */
3752b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3753b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The 'exp()' case must invert the above, taking a 20-bit fixed point
3754b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * logarithmic value and returning a 16 or 8-bit number as appropriate.  In
3755b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * each case only the low 16 bits are relevant - the fraction - since the
3756b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * integer bits (the top 4) simply determine a shift.
3757b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
37589b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The worst case is the 16-bit distinction between 65535 and 65534. This
37599b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * requires perhaps spurious accuracy in the decoding of the logarithm to
3760b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * distinguish log2(65535/65534.5) - 10^-5 or 17 bits.  There is little chance
3761b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * of getting this accuracy in practice.
3762b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3763b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * To deal with this the following exp() function works out the exponent of the
37643cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * fractional part of the logarithm by using an accurate 32-bit value from the
3765b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * top four fractional bits then multiplying in the remaining bits.
3766b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3767b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic const png_uint_32
3768b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_32bit_exp[16] =
3769b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3770b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */
3771b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U,
3772b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U,
3773b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2553802834U, 2445529972U, 2341847524U, 2242560872U
3774b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
3775b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3776b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Adjustment table; provided to explain the numbers in the code below. */
3777b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if 0
3778b50c217251b086440efcdb273c22f86a06c80cbaChris Craikfor (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"}
3779b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   11 44937.64284865548751208448
3780b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10 45180.98734845585101160448
3781b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    9 45303.31936980687359311872
3782b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    8 45364.65110595323018870784
3783b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    7 45395.35850361789624614912
3784b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    6 45410.72259715102037508096
3785b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    5 45418.40724413220722311168
3786b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    4 45422.25021786898173001728
3787b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    3 45424.17186732298419044352
3788b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    2 45425.13273269940811464704
3789b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    1 45425.61317555035558641664
3790b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    0 45425.85339951654943850496
37915f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott#endif
3792b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3793b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_32
3794b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_exp(png_fixed_point x)
3795b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3796b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */
37975f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
3798b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Obtain a 4-bit approximation */
37999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f];
3800b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3801b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Incorporate the low 12 bits - these decrease the returned value by
3802b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * multiplying by a number less than 1 if the bit is set.  The multiplier
3803b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * is determined by the above table and the shift. Notice that the values
3804b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * converge on 45426 and this is used to allow linear interpolation of the
3805b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * low bits.
3806b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
3807b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x800)
3808b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 44938U) +  16U) >> 5;
3809b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3810b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x400)
3811b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 45181U) +  32U) >> 6;
3812b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3813b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x200)
3814b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 45303U) +  64U) >> 7;
3815b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3816b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x100)
3817b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 45365U) + 128U) >> 8;
3818b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3819b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x080)
3820b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 45395U) + 256U) >> 9;
3821b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3822b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      if (x & 0x040)
3823b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         e -= (((e >> 16) * 45410U) + 512U) >> 10;
3824b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3825b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* And handle the low 6 bits in a single block. */
3826b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9;
3827b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3828b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Handle the upper bits of x. */
3829b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      e >>= x >> 16;
3830b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return e;
38315f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
38325f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
3833b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Check for overflow */
3834b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (x <= 0)
3835b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_32bit_exp[0];
3836b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3837b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Else underflow */
3838b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
3839b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3840b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3841b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_byte
3842b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_exp8bit(png_fixed_point lg2)
3843b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3844b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Get a 32-bit value: */
3845b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 x = png_exp(lg2);
3846b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
38479b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the
3848b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * second, rounding, step can't overflow because of the first, subtraction,
3849b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * step.
3850b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
3851b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   x -= x >> 8;
38529b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff);
3853b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3854b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3855b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
3856b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic png_uint_16
3857b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_exp16bit(png_fixed_point lg2)
3858b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3859b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Get a 32-bit value: */
3860b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 x = png_exp(lg2);
3861b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3862b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */
3863b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   x -= x >> 16;
3864b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (png_uint_16)((x + 32767U) >> 16);
3865b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3866b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
3867b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* FLOATING_ARITHMETIC */
3868b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3869b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_byte
3870b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val)
3871b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3872b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (value > 0 && value < 255)
38735f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
3874b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
38759b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly
38769b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * convert this to a floating point value.  This includes values that
38779b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * would overflow if 'value' were to be converted to 'int'.
38789b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          *
38799b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * Apparently GCC, however, does an intermediate conversion to (int)
38809b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * on some (ARM) but not all (x86) platforms, possibly because of
38819b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * hardware FP limitations.  (E.g. if the hardware conversion always
38829b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * assumes the integer register contains a signed value.)  This results
38839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * in ANSI-C undefined behavior for large values.
38849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          *
38859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * Other implementations on the same machine might actually be ANSI-C90
38869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * conformant and therefore compile spurious extra code for the large
38879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * values.
38889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          *
38899b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * We can be reasonably sure that an unsigned to float conversion
38909b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * won't be faster than an int to float one.  Therefore this code
38919b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * assumes responsibility for the undefined behavior, which it knows
38929b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * can't happen because of the check above.
38939b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          *
38949b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * Note the argument to this routine is an (unsigned int) because, on
38959b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * 16-bit platforms, it is assigned a value which might be out of
38969b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * range for an (int); that would result in undefined behavior in the
38979b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          * caller if the *argument* ('value') were to be declared (int).
38989b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett          */
38999b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5);
3900b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         return (png_byte)r;
3901b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     else
3902b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_int_32 lg2 = png_log8bit(value);
3903b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_fixed_point res;
3904b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
39059b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)
3906b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            return png_exp8bit(res);
3907b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3908b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Overflow. */
3909b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         value = 0;
3910b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
39115f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
39125f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
39139b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   return (png_byte)(value & 0xff);
3914b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3915b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3916b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
3917b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_uint_16
3918b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val)
3919b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3920b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (value > 0 && value < 65535)
39215f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
39227a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
39237a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      /* The same (unsigned int)->(double) constraints apply here as above,
39247a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * however in this case the (unsigned int) to (int) conversion can
39257a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * overflow on an ANSI-C90 compliant system so the cast needs to ensure
39267a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * that this is not possible.
39277a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       */
39287a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      double r = floor(65535*pow((png_int_32)value/65535.,
39297a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          gamma_val*.00001)+.5);
39307a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      return (png_uint_16)r;
39317a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis# else
39327a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_int_32 lg2 = png_log16bit(value);
39337a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_fixed_point res;
39347a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
39357a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0)
39367a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         return png_exp16bit(res);
39377a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
39387a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      /* Overflow. */
39397a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      value = 0;
39407a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis# endif
39415f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
39425f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
3943b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return (png_uint_16)value;
3944b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3945b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
3946b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3947b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* This does the right thing based on the bit_depth field of the
3948b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_struct, interpreting values as 8-bit or 16-bit.  While the result
3949b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is nominally a 16-bit value if bit depth is 8 then the result is
3950b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 8-bit (as are the arguments.)
3951b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3952b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_uint_16 /* PRIVATE */
3953b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_gamma_correct(png_structrp png_ptr, unsigned int value,
3954b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    png_fixed_point gamma_val)
3955b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3956b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr->bit_depth == 8)
3957b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_gamma_8bit_correct(value, gamma_val);
3958b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3959b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
3960b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
3961b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return png_gamma_16bit_correct(value, gamma_val);
3962b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#else
3963b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      /* should not reach this */
3964b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari      return 0;
3965b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
3966b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
3967b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3968b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
3969b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Internal function to build a single 16-bit table - the table consists of
3970b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount
3971b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * to shift the input values right (or 16-number_of_signifiant_bits).
3972b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
3973b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The caller is responsible for ensuring that the table gets cleaned up on
3974b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument
3975b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * should be somewhere that will be cleaned.
3976b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
3977b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void
3978b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable,
39797a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
3980b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
3981b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Various values derived from 'shift': */
3982b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CONST unsigned int num = 1U << (8U - shift);
39839b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
39849b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   /* CSE the division and work round wacky GCC warnings (see the comments
39859b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * in png_gamma_8bit_correct for where these come from.)
39869b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    */
39879b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1);
39889b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif
3989b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
3990b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CONST unsigned int max_by_2 = 1U << (15U-shift);
3991b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int i;
3992b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3993b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_16pp table = *ptable =
3994b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));
3995b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
3996b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   for (i = 0; i < num; i++)
39975f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
3998b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_16p sub_table = table[i] =
3999b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16)));
4000b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4001b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* The 'threshold' test is repeated here because it can arise for one of
4002b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       * the 16-bit tables even if the others don't hit it.
4003b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       */
40049b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (png_gamma_significant(gamma_val) != 0)
4005b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4006b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* The old code would overflow at the end and this would cause the
4007b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * 'pow' function to return a result >1, resulting in an
4008b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * arithmetic error.  This code follows the spec exactly; ig is
4009b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * the recovered input sample, it always has 8-16 bits.
4010b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          *
4011b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * We want input * 65535/max, rounded, the arithmetic fits in 32
4012b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          * bits (unsigned) so long as max <= 32767.
4013b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          */
4014b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         unsigned int j;
4015b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         for (j = 0; j < 256; j++)
4016b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
4017b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_uint_32 ig = (j << (8-shift)) + i;
4018b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#           ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
4019b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               /* Inline the 'max' scaling operation: */
40209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               /* See png_gamma_8bit_correct for why the cast to (int) is
40219b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                * required here.
40229b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett                */
40239b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5);
4024b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               sub_table[j] = (png_uint_16)d;
4025b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#           else
40269b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett               if (shift != 0)
4027b50c217251b086440efcdb273c22f86a06c80cbaChris Craik                  ig = (ig * 65535U + max_by_2)/max;
4028b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4029b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
4030b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#           endif
4031b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
4032b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
4033b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      else
4034b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4035b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* We must still build a table, but do it the fast way. */
4036b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         unsigned int j;
4037b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4038b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         for (j = 0; j < 256; j++)
4039b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
4040b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            png_uint_32 ig = (j << (8-shift)) + i;
4041b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
40429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett            if (shift != 0)
4043b50c217251b086440efcdb273c22f86a06c80cbaChris Craik               ig = (ig * 65535U + max_by_2)/max;
4044b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4045b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            sub_table[j] = (png_uint_16)ig;
4046b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
4047b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
40485f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
4049b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
40505f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4051b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* NOTE: this function expects the *inverse* of the overall gamma transformation
4052b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * required.
4053b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4054b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void
4055b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable,
40567a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val)
4057b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4058b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CONST unsigned int num = 1U << (8U - shift);
4059b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   PNG_CONST unsigned int max = (1U << (16U - shift))-1U;
4060b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int i;
4061b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_32 last;
40625f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4063b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_uint_16pp table = *ptable =
4064b50c217251b086440efcdb273c22f86a06c80cbaChris Craik       (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p)));
4065b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4066b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* 'num' is the number of tables and also the number of low bits of low
4067b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * bits of the input 16-bit value used to select a table.  Each table is
40689b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett    * itself indexed by the high 8 bits of the value.
4069b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
4070b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   for (i = 0; i < num; i++)
4071b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      table[i] = (png_uint_16p)png_malloc(png_ptr,
4072b50c217251b086440efcdb273c22f86a06c80cbaChris Craik          256 * (sizeof (png_uint_16)));
4073b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4074b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* 'gamma_val' is set to the reciprocal of the value calculated above, so
4075b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * pow(out,g) is an *input* value.  'last' is the last input value set.
4076b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
4077b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * In the loop 'i' is used to find output values.  Since the output is
4078b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 8-bit there are only 256 possible values.  The tables are set up to
4079b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * select the closest possible output value for each input by finding
4080b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * the input value at the boundary between each pair of output values
4081b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * and filling the table up to that boundary with the lower output
4082b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * value.
4083b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    *
4084b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * The boundary values are 0.5,1.5..253.5,254.5.  Since these are 9-bit
4085b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * values the code below uses a 16-bit value in i; the values start at
4086b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last
4087b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * entries are filled with 255).  Start i at 128 and fill all 'last'
4088b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * table entries <= 'max'
4089b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
4090b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   last = 0;
4091b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   for (i = 0; i < 255; ++i) /* 8-bit output value */
40925f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
4093b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Find the corresponding maximum input value */
4094b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */
4095b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4096b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Find the boundary value in 16 bits: */
4097b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val);
4098b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4099b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Adjust (round) to (16-shift) bits: */
4100b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      bound = (bound * max + 32768U)/65535U + 1U;
4101b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4102b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      while (last < bound)
4103b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4104b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         table[last & (0xffU >> shift)][last >> (8U - shift)] = out;
4105b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         last++;
4106b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
41075f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
41085f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4109b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* And fill in the final entries. */
4110b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   while (last < (num << 8))
41115f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
4112b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U;
4113b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      last++;
41145f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
4115b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
4116b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
41175f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4118b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Build a single 8-bit table: same as the 16-bit case but much simpler (and
4119b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * typically much faster).  Note that libpng currently does no sBIT processing
41209b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * (apparently contrary to the spec) so a 256-entry table is always generated.
4121b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4122b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic void
4123b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_build_8bit_table(png_structrp png_ptr, png_bytepp ptable,
41247a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    PNG_CONST png_fixed_point gamma_val)
4125b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4126b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   unsigned int i;
4127b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256);
4128b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
41299b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (png_gamma_significant(gamma_val) != 0)
41309b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      for (i=0; i<256; i++)
41319b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         table[i] = png_gamma_8bit_correct(i, gamma_val);
4132b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
41339b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   else
41349b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      for (i=0; i<256; ++i)
41359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett         table[i] = (png_byte)(i & 0xff);
4136b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
4137b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4138b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* Used from png_read_destroy and below to release the memory used by the gamma
4139b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * tables.
4140b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4141b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
4142b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_destroy_gamma_table(png_structrp png_ptr)
4143b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4144b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_table);
4145b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_table = NULL;
4146b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4147b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
4148b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr->gamma_16_table != NULL)
41495f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
4150b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int i;
4151b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int istop = (1 << (8 - png_ptr->gamma_shift));
4152b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      for (i = 0; i < istop; i++)
4153b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4154b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_free(png_ptr, png_ptr->gamma_16_table[i]);
4155b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
4156b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_16_table);
4157b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_16_table = NULL;
41585f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
4159b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
41605f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4161b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4162b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
4163b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
4164b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_from_1);
4165b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_from_1 = NULL;
4166b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_to_1);
4167b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_to_1 = NULL;
4168b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4169b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
4170b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr->gamma_16_from_1 != NULL)
41715f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
4172b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int i;
4173b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int istop = (1 << (8 - png_ptr->gamma_shift));
4174b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      for (i = 0; i < istop; i++)
4175b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4176b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
4177b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
4178b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_16_from_1);
4179b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_16_from_1 = NULL;
4180b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
4181b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr->gamma_16_to_1 != NULL)
4182b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
4183b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int i;
4184b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      int istop = (1 << (8 - png_ptr->gamma_shift));
4185b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      for (i = 0; i < istop; i++)
4186b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      {
4187b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
4188b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      }
4189b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(png_ptr, png_ptr->gamma_16_to_1);
4190b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_ptr->gamma_16_to_1 = NULL;
41915f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
4192b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
4193b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
4194b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
41955f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4196b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* We build the 8- or 16-bit gamma tables here.  Note that for 16-bit
4197b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * tables, we don't make a full table if we are reducing to 8-bit in
4198b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * the future.  Note also how the gamma_16 tables are segmented so that
4199b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * we don't need to allocate > 64K chunks for a full 16-bit table.
4200b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4201b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid /* PRIVATE */
4202b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_build_gamma_table(png_structrp png_ptr, int bit_depth)
4203b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
42047a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   png_debug(1, "in png_build_gamma_table");
42057a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42067a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   /* Remove any existing table; this copes with multiple calls to
42077a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * png_read_update_info. The warning is because building the gamma tables
42087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * multiple times is a performance hit - it's harmless but the ability to
42097a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * call png_read_update_info() multiple times is new in 1.5.6 so it seems
42107a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    * sensible to warn if the app introduces such a hit.
42117a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis    */
42127a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL)
42137a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   {
42147a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_warning(png_ptr, "gamma table being rebuilt");
42157a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_destroy_gamma_table(png_ptr);
42167a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   }
42177a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42187a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   if (bit_depth <= 8)
42197a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   {
42207a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_build_8bit_table(png_ptr, &png_ptr->gamma_table,
42217a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma > 0 ?
42227a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_reciprocal2(png_ptr->colorspace.gamma,
42237a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma) : PNG_FP_1);
4224b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4225b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4226b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
4227b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
42287a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
42297a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      {
42307a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1,
42317a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_reciprocal(png_ptr->colorspace.gamma));
42327a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42337a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1,
42347a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_ptr->screen_gamma > 0 ?
42357a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_reciprocal(png_ptr->screen_gamma) :
42367a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
42377a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      }
4238b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
42397a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   }
4240b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#ifdef PNG_16BIT_SUPPORTED
42417a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   else
42427a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   {
42437a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_byte shift, sig_bit;
42447a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42457a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
42467a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      {
42477a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         sig_bit = png_ptr->sig_bit.red;
42487a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42497a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         if (png_ptr->sig_bit.green > sig_bit)
42507a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis            sig_bit = png_ptr->sig_bit.green;
42517a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42527a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         if (png_ptr->sig_bit.blue > sig_bit)
42537a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis            sig_bit = png_ptr->sig_bit.blue;
42547a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      }
42557a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else
42567a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         sig_bit = png_ptr->sig_bit.gray;
42577a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42587a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      /* 16-bit gamma code uses this equation:
42597a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42607a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *   ov = table[(iv & 0xff) >> gamma_shift][iv >> 8]
42617a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42627a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * Where 'iv' is the input color value and 'ov' is the output value -
42637a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * pow(iv, gamma).
42647a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42657a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * Thus the gamma table consists of up to 256 256-entry tables.  The table
42667a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * is selected by the (8-gamma_shift) most significant of the low 8 bits
42677a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * of the color value then indexed by the upper 8 bits:
42687a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42697a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *   table[low bits][high 8 bits]
42707a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42717a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * So the table 'n' corresponds to all those 'iv' of:
42727a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42737a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *   <all high 8-bit values><n << gamma_shift>..<(n+1 << gamma_shift)-1>
42747a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       *
42757a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       */
42767a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if (sig_bit > 0 && sig_bit < 16U)
42777a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         /* shift == insignificant bits */
42787a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         shift = (png_byte)((16U - sig_bit) & 0xff);
42797a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42807a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else
42817a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         shift = 0; /* keep all 16 bits */
42827a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42837a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)
42847a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      {
42857a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively
42867a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          * the significant bits in the *input* when the output will
42877a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          * eventually be 8 bits.  By default it is 11.
42887a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          */
42897a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         if (shift < (16U - PNG_MAX_GAMMA_8))
42907a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis            shift = (16U - PNG_MAX_GAMMA_8);
42917a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      }
42927a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42937a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if (shift > 8U)
42947a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         shift = 8U; /* Guarantees at least one table! */
42957a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42967a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      png_ptr->gamma_shift = shift;
42977a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
42987a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now
42997a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * PNG_COMPOSE).  This effectively smashed the background calculation for
43007a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * 16-bit output because the 8-bit table assumes the result will be
43017a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       * reduced to 8 bits.
43027a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis       */
43037a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0)
43047a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift,
43057a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma,
43067a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma) : PNG_FP_1);
43077a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
43087a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      else
43097a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift,
43107a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma,
43117a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          png_ptr->screen_gamma) : PNG_FP_1);
4312b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4313b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
4314b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \
4315b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
43167a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0)
43177a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      {
43187a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift,
43197a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_reciprocal(png_ptr->colorspace.gamma));
43207a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis
43217a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         /* Notice that the '16 from 1' table should be full precision, however
43227a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          * the lookup on this table still uses gamma_shift, so it can't be.
43237a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          * TODO: fix this.
43247a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis          */
43257a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis         png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift,
43267a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) :
43277a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis             png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */);
43287a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis      }
4329b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */
43307a055fdaacbcb54d3606638017fb3381f05d96acAlex Naidis   }
4331b478e66e7c2621eef5f465e4629ce642db00716bSireesh Tripurari#endif /* 16BIT */
4332b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
4333b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* READ_GAMMA */
4334b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
43359b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett/* HARDWARE OR SOFTWARE OPTION SUPPORT */
4336b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_SET_OPTION_SUPPORTED
4337b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint PNGAPI
4338b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_set_option(png_structrp png_ptr, int option, int onoff)
4339b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4340b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&
4341b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (option & 1) == 0)
43425f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
43433cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      png_uint_32 mask = 3U << option;
43443cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      png_uint_32 setting = (2U + (onoff != 0)) << option;
43453cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      png_uint_32 current = png_ptr->options;
4346b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
43473cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      png_ptr->options = (png_uint_32)(((current & ~mask) | setting) & 0xff);
4348b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
43493cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III      return (int)(current & mask) >> option;
43505f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
43515f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4352b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return PNG_OPTION_INVALID;
4353b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
4354b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif
4355b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4356b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* sRGB support */
4357b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
4358b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
4359b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* sRGB conversion tables; these are machine generated with the code in
4360b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * contrib/tools/makesRGB.c.  The actual sRGB transfer curve defined in the
43613cc83ac4b563ffa7a1bae9572f5fc3c1ee5f8a10Leon Scroggins III * specification (see the article at https://en.wikipedia.org/wiki/SRGB)
4362b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * is used, not the gamma=1/2.2 approximation use elsewhere in libpng.
43639b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * The sRGB to linear table is exact (to the nearest 16-bit linear fraction).
4364b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * The inverse (linear to sRGB) table has accuracies as follows:
4365b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
4366b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * For all possible (255*65535+1) input values:
4367b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
4368b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *    error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact
4369b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
4370b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * For the input values corresponding to the 65536 16-bit values:
4371b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
4372b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *    error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact
4373b50c217251b086440efcdb273c22f86a06c80cbaChris Craik *
43749b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett * In all cases the inexact readings are only off by one.
4375b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4376b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4377b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
4378b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The convert-to-sRGB table is only currently required for read. */
4379b50c217251b086440efcdb273c22f86a06c80cbaChris Craikconst png_uint_16 png_sRGB_table[256] =
4380b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4381b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   0,20,40,60,80,99,119,139,
4382b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   159,179,199,219,241,264,288,313,
4383b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   340,367,396,427,458,491,526,562,
4384b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   599,637,677,718,761,805,851,898,
4385b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   947,997,1048,1101,1156,1212,1270,1330,
4386b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1391,1453,1517,1583,1651,1720,1790,1863,
4387b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   1937,2013,2090,2170,2250,2333,2418,2504,
4388b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   2592,2681,2773,2866,2961,3058,3157,3258,
4389b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   3360,3464,3570,3678,3788,3900,4014,4129,
4390b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   4247,4366,4488,4611,4736,4864,4993,5124,
4391b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   5257,5392,5530,5669,5810,5953,6099,6246,
4392b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   6395,6547,6700,6856,7014,7174,7335,7500,
4393b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   7666,7834,8004,8177,8352,8528,8708,8889,
4394b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   9072,9258,9445,9635,9828,10022,10219,10417,
4395b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10619,10822,11028,11235,11446,11658,11873,12090,
4396b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   12309,12530,12754,12980,13209,13440,13673,13909,
4397b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   14146,14387,14629,14874,15122,15371,15623,15878,
4398b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   16135,16394,16656,16920,17187,17456,17727,18001,
4399b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   18277,18556,18837,19121,19407,19696,19987,20281,
4400b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   20577,20876,21177,21481,21787,22096,22407,22721,
4401b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   23038,23357,23678,24002,24329,24658,24990,25325,
4402b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   25662,26001,26344,26688,27036,27386,27739,28094,
4403b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   28452,28813,29176,29542,29911,30282,30656,31033,
4404b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   31412,31794,32179,32567,32957,33350,33745,34143,
4405b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   34544,34948,35355,35764,36176,36591,37008,37429,
4406b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   37852,38278,38706,39138,39572,40009,40449,40891,
4407b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   41337,41785,42236,42690,43147,43606,44069,44534,
4408b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   45002,45473,45947,46423,46903,47385,47871,48359,
4409b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   48850,49344,49841,50341,50844,51349,51858,52369,
4410b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   52884,53401,53921,54445,54971,55500,56032,56567,
4411b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   57105,57646,58190,58737,59287,59840,60396,60955,
4412b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   61517,62082,62650,63221,63795,64372,64952,65535
4413b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
44149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* SIMPLIFIED_READ */
4415b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4416b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* The base/delta tables are required for both read and write (but currently
4417b50c217251b086440efcdb273c22f86a06c80cbaChris Craik * only the simplified versions.)
4418b50c217251b086440efcdb273c22f86a06c80cbaChris Craik */
4419b50c217251b086440efcdb273c22f86a06c80cbaChris Craikconst png_uint_16 png_sRGB_base[512] =
4420b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4421b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   128,1782,3383,4644,5675,6564,7357,8074,
4422b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8732,9346,9921,10463,10977,11466,11935,12384,
4423b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   12816,13233,13634,14024,14402,14769,15125,15473,
4424b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   15812,16142,16466,16781,17090,17393,17690,17981,
4425b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   18266,18546,18822,19093,19359,19621,19879,20133,
4426b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   20383,20630,20873,21113,21349,21583,21813,22041,
4427b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   22265,22487,22707,22923,23138,23350,23559,23767,
4428b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   23972,24175,24376,24575,24772,24967,25160,25352,
4429b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   25542,25730,25916,26101,26284,26465,26645,26823,
4430b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   27000,27176,27350,27523,27695,27865,28034,28201,
4431b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   28368,28533,28697,28860,29021,29182,29341,29500,
4432b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   29657,29813,29969,30123,30276,30429,30580,30730,
4433b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   30880,31028,31176,31323,31469,31614,31758,31902,
4434b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   32045,32186,32327,32468,32607,32746,32884,33021,
4435b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   33158,33294,33429,33564,33697,33831,33963,34095,
4436b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   34226,34357,34486,34616,34744,34873,35000,35127,
4437b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   35253,35379,35504,35629,35753,35876,35999,36122,
4438b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   36244,36365,36486,36606,36726,36845,36964,37083,
4439b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   37201,37318,37435,37551,37668,37783,37898,38013,
4440b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   38127,38241,38354,38467,38580,38692,38803,38915,
4441b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   39026,39136,39246,39356,39465,39574,39682,39790,
4442b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   39898,40005,40112,40219,40325,40431,40537,40642,
4443b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   40747,40851,40955,41059,41163,41266,41369,41471,
4444b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   41573,41675,41777,41878,41979,42079,42179,42279,
4445b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   42379,42478,42577,42676,42775,42873,42971,43068,
4446b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   43165,43262,43359,43456,43552,43648,43743,43839,
4447b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   43934,44028,44123,44217,44311,44405,44499,44592,
4448b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   44685,44778,44870,44962,45054,45146,45238,45329,
4449b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   45420,45511,45601,45692,45782,45872,45961,46051,
4450b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   46140,46229,46318,46406,46494,46583,46670,46758,
4451b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   46846,46933,47020,47107,47193,47280,47366,47452,
4452b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   47538,47623,47709,47794,47879,47964,48048,48133,
4453b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   48217,48301,48385,48468,48552,48635,48718,48801,
4454b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   48884,48966,49048,49131,49213,49294,49376,49458,
4455b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   49539,49620,49701,49782,49862,49943,50023,50103,
4456b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   50183,50263,50342,50422,50501,50580,50659,50738,
4457b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   50816,50895,50973,51051,51129,51207,51285,51362,
4458b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   51439,51517,51594,51671,51747,51824,51900,51977,
4459b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   52053,52129,52205,52280,52356,52432,52507,52582,
4460b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   52657,52732,52807,52881,52956,53030,53104,53178,
4461b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   53252,53326,53400,53473,53546,53620,53693,53766,
4462b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   53839,53911,53984,54056,54129,54201,54273,54345,
4463b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   54417,54489,54560,54632,54703,54774,54845,54916,
4464b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   54987,55058,55129,55199,55269,55340,55410,55480,
4465b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   55550,55620,55689,55759,55828,55898,55967,56036,
4466b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   56105,56174,56243,56311,56380,56448,56517,56585,
4467b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   56653,56721,56789,56857,56924,56992,57059,57127,
4468b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   57194,57261,57328,57395,57462,57529,57595,57662,
4469b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   57728,57795,57861,57927,57993,58059,58125,58191,
4470b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   58256,58322,58387,58453,58518,58583,58648,58713,
4471b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   58778,58843,58908,58972,59037,59101,59165,59230,
4472b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   59294,59358,59422,59486,59549,59613,59677,59740,
4473b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   59804,59867,59930,59993,60056,60119,60182,60245,
4474b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   60308,60370,60433,60495,60558,60620,60682,60744,
4475b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   60806,60868,60930,60992,61054,61115,61177,61238,
4476b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   61300,61361,61422,61483,61544,61605,61666,61727,
4477b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   61788,61848,61909,61969,62030,62090,62150,62211,
4478b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   62271,62331,62391,62450,62510,62570,62630,62689,
4479b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   62749,62808,62867,62927,62986,63045,63104,63163,
4480b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   63222,63281,63340,63398,63457,63515,63574,63632,
4481b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   63691,63749,63807,63865,63923,63981,64039,64097,
4482b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   64155,64212,64270,64328,64385,64443,64500,64557,
4483b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   64614,64672,64729,64786,64843,64900,64956,65013,
4484b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   65070,65126,65183,65239,65296,65352,65409,65465
4485b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
4486b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4487b50c217251b086440efcdb273c22f86a06c80cbaChris Craikconst png_byte png_sRGB_delta[512] =
4488b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4489b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54,
4490b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36,
4491b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28,
4492b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24,
4493b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21,
4494b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19,
4495b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,
4496b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16,
4497b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15,
4498b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14,
4499b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,
4500b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12,
4501b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
4502b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11,
4503b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
4504b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
4505b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
4506b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
4507b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
4508b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
4509b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
4510b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
4511b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
4512b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
4513b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
4514b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
4515b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
4516b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
4517b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7,
4518b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
4519b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
4520b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
4521b50c217251b086440efcdb273c22f86a06c80cbaChris Craik};
4522b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* SIMPLIFIED READ/WRITE sRGB support */
4523b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4524b50c217251b086440efcdb273c22f86a06c80cbaChris Craik/* SIMPLIFIED READ/WRITE SUPPORT */
4525b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
4526b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
4527b50c217251b086440efcdb273c22f86a06c80cbaChris Craikstatic int
4528b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_image_free_function(png_voidp argument)
4529b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4530b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_imagep image = png_voidcast(png_imagep, argument);
4531b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_controlp cp = image->opaque;
4532b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_control c;
4533b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4534b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Double check that we have a png_ptr - it should be impossible to get here
4535b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * without one.
45365f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott    */
4537b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (cp->png_ptr == NULL)
4538b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      return 0;
45395f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4540b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* First free any data held in the control structure. */
4541b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  ifdef PNG_STDIO_SUPPORTED
45429b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett      if (cp->owned_file != 0)
45435f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott      {
4544b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr);
4545b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         cp->owned_file = 0;
45465f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4547b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         /* Ignore errors here. */
4548b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         if (fp != NULL)
4549b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         {
4550b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            cp->png_ptr->io_ptr = NULL;
4551b50c217251b086440efcdb273c22f86a06c80cbaChris Craik            (void)fclose(fp);
4552b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         }
45535f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott      }
4554b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#  endif
4555b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4556b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Copy the control structure so that the original, allocated, version can be
4557b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * safely freed.  Notice that a png_error here stops the remainder of the
4558b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * cleanup, but this is probably fine because that would indicate bad memory
4559b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * problems anyway.
4560b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
4561b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   c = *cp;
4562b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   image->opaque = &c;
4563b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_free(c.png_ptr, cp);
4564b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4565b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Then the structures, calling the correct API. */
45669b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett   if (c.for_write != 0)
4567b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
4568b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
4569b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_destroy_write_struct(&c.png_ptr, &c.info_ptr);
4570b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     else
4571b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_error(c.png_ptr, "simplified write not supported");
4572b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
4573b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   }
4574b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   else
4575b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   {
4576b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     ifdef PNG_SIMPLIFIED_READ_SUPPORTED
4577b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL);
4578b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     else
4579b50c217251b086440efcdb273c22f86a06c80cbaChris Craik         png_error(c.png_ptr, "simplified read not supported");
4580b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#     endif
45815f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
45825f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4583b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Success. */
4584b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 1;
4585b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
4586b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4587b50c217251b086440efcdb273c22f86a06c80cbaChris Craikvoid PNGAPI
4588b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_image_free(png_imagep image)
4589b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4590b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Safely call the real function, but only if doing so is safe at this point
4591b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * (if not inside an error handling context).  Otherwise assume
4592b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    * png_safe_execute will call this API after the return.
4593b50c217251b086440efcdb273c22f86a06c80cbaChris Craik    */
4594b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   if (image != NULL && image->opaque != NULL &&
4595b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      image->opaque->error_buf == NULL)
45965f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   {
4597b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      /* Ignore errors here: */
4598b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      (void)png_safe_execute(image, png_image_free_function, image);
4599b50c217251b086440efcdb273c22f86a06c80cbaChris Craik      image->opaque = NULL;
46005f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott   }
4601b50c217251b086440efcdb273c22f86a06c80cbaChris Craik}
46025f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott
4603b50c217251b086440efcdb273c22f86a06c80cbaChris Craikint /* PRIVATE */
4604b50c217251b086440efcdb273c22f86a06c80cbaChris Craikpng_image_error(png_imagep image, png_const_charp error_message)
4605b50c217251b086440efcdb273c22f86a06c80cbaChris Craik{
4606b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   /* Utility to log an error. */
4607b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_safecat(image->message, (sizeof image->message), 0, error_message);
4608b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   image->warning_or_error |= PNG_IMAGE_ERROR;
4609b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   png_image_free(image);
4610b50c217251b086440efcdb273c22f86a06c80cbaChris Craik   return 0;
46115f6bd84e375226bf228fc8ac90318957ec9e1e7fPatrick Scott}
4612b50c217251b086440efcdb273c22f86a06c80cbaChris Craik
4613b50c217251b086440efcdb273c22f86a06c80cbaChris Craik#endif /* SIMPLIFIED READ/WRITE */
46149b1fe63dcc7ba076b9730b7bfa031cc0dbc25561Matt Sarett#endif /* READ || WRITE */
4615