[libpng16] Recognize known sRGB ICC profiles while reading; prefer writing the

    iCCP profile over writing the sRGB chunk, controlled by the
    PNG_sRGB_PROFILE_CHECKS option.
diff --git a/ANNOUNCE b/ANNOUNCE
index 3fb484e..bef84dc 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -1,5 +1,5 @@
 
-Libpng 1.6.0beta20 - March 28, 2012
+Libpng 1.6.0beta20 - March 29, 2012
 
 This is not intended to be a public release.  It will be replaced
 within a few weeks by a public version or by another test version.
@@ -339,12 +339,14 @@
   Avoid the double gamma correction warning in the simplified API.
     This allows the --strict option to pass in the pngstest checks
 
-Version 1.6.0beta20 [March 28, 2012]
+Version 1.6.0beta20 [March 29, 2012]
   Changed chunk handler warnings into benign errors, incrementally load iCCP
-  Recognize known sRGB ICC profiles while reading and issue a warning about
-    it, if PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED is defined.
   Added checksum-icc.c to contrib/tools
   Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice.
+  Recognize known sRGB ICC profiles while reading; prefer writing the
+    iCCP profile over writing the sRGB chunk, controlled by the
+    PNG_sRGB_PROFILE_CHECKS option.
+  Revised png_set_text_2() to avoid potential memory corruption.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/CHANGES b/CHANGES
index 97c7e2c..024c050 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4090,12 +4090,14 @@
   Avoid the double gamma correction warning in the simplified API.
     This allows the --strict option to pass in the pngstest checks
 
-Version 1.6.0beta20 [March 28, 2012]
+Version 1.6.0beta20 [March 29, 2012]
   Changed chunk handler warnings into benign errors, incrementally load iCCP
-  Recognize known sRGB ICC profiles while reading and issue a warning about
-    it, if PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED is defined.
   Added checksum-icc.c to contrib/tools
   Prevent PNG_EXPAND+PNG_SHIFT doing the shift twice.
+  Recognize known sRGB ICC profiles while reading; prefer writing the
+    iCCP profile over writing the sRGB chunk, controlled by the
+    PNG_sRGB_PROFILE_CHECKS option.
+  Revised png_set_text_2() to avoid potential memory corruption.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/png.c b/png.c
index 24f4a17..e44e939 100644
--- a/png.c
+++ b/png.c
@@ -747,13 +747,13 @@
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-     "libpng version 1.6.0beta20 - March 21, 2012" PNG_STRING_NEWLINE \
+     "libpng version 1.6.0beta20 - March 29, 2012" PNG_STRING_NEWLINE \
      "Copyright (c) 1998-2012 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
      PNG_STRING_NEWLINE;
 #  else
-      return "libpng version 1.6.0beta20 - March 21, 2012\
+      return "libpng version 1.6.0beta20 - March 29, 2012\
       Copyright (c) 1998-2012 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
@@ -1974,17 +1974,192 @@
    return 1;
 }
 
-void /* PRIVATE */
+#ifdef PNG_sRGB_SUPPORTED
+/* Information about the known ICC sRGB profiles */
+static const struct
+{
+   png_uint_32 adler, crc, length;
+   png_uint_32 md5[4];
+   png_uint_16 have_md5;
+   png_uint_16 intent;
+
+#  define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0)
+#  define PNG_ICC_CHECKSUM(adler, crc, md5, intent, date, length, fname)\
+      { adler, crc, length, md5, intent },
+
+} png_sRGB_checks[] =
+{
+   /* This data comes from contrib/tools/checksum-icc run on downloads of
+    * all four ICC sRGB profiles from www.color.org.
+    */
+   /* adler32, crc32, MD5[4], intent, date, length, file-name */
+   PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9,
+      PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0,
+      "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc")
+
+   /* ICC sRGB v2 perceptual no black-compensation: */
+   PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21,
+      PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1,
+      "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc")
+
+   PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae,
+      PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0,
+      "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc")
+
+   /* ICC sRGB v4 perceptual */
+   PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812,
+      PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0,
+      "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc")
+
+   /* The following profiles have no known MD5 checksum, if there is a match
+    * on the (empty) MD5 the other fields are used to attempt a match and
+    * a warning is produced.  The first two of these profiles have a 'cprt' tag
+    * which suggests that they were also made by Hewlett Packard.
+    */
+   PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce,
+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1,
+      "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc")
+
+   PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552,
+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0,
+      "1998/02/09 06:49:00", 3144, "sRGB Profile.icc")
+
+   PNG_ICC_CHECKSUM(0x0398f3fcUL, 0xf29e526dUL,
+      PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0,
+      "unknown", 3144, "HP-Microsoft sRGB v2 perceptual")
+};
+
+static int
+png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr,
+   png_const_bytep profile, uLong adler)
+{
+   /* The quick check is to verify just the MD5 signature and trust to the
+    * rest of the data.  Because the profile has already been verified for
+    * correctness this is safe.  png_colorspace_set_sRGB will check the 'intent'
+    * field too, so if the profile has been editted with an intent not defined
+    * by sRGB (but maybe defined by a later ICC specification) the read of
+    * the profile will fail at that point.
+    */
+   png_uint_32 length = 0;
+   png_uint_32 intent = 0x10000; /* invalid */
+#if PNG_sRGB_PROFILE_CHECKS > 1
+   uLong crc = 0; /* the value for 0 length data */
+#endif
+   unsigned int i;
+
+   for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i)
+   {
+      if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] &&
+         png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] &&
+         png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] &&
+         png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3])
+      {
+         /* This may be one of the old HP profiles without an MD5, in that
+          * case we can only use the length and Adler32 (note that these
+          * are not used by default if there is an MD5!)
+          */
+#        if PNG_sRGB_PROFILE_CHECKS == 0
+            if (png_sRGB_checks[i].have_md5)
+               return 1;
+#        endif
+
+         /* Profile is unsigned or more checks have been configured in. */
+         if (length == 0)
+         {
+            length = png_get_uint_32(profile);
+            intent = png_get_uint_32(profile+64);
+         }
+
+         /* Length *and* intent must match */
+         if (length == png_sRGB_checks[i].length &&
+            intent == png_sRGB_checks[i].intent)
+         {
+            /* Now calculate the alder32 if not done already. */
+            if (adler == 0)
+            {
+               adler = adler32(0, NULL, 0);
+               adler = adler32(adler, profile, length);
+            }
+
+            if (adler == png_sRGB_checks[i].adler)
+            {
+               /* These basic checks suggest that the data has not been
+                * modified, but if the check level is more than 1 perform
+                * our own crc32 checksum on the data.
+                */
+#              if PNG_sRGB_PROFILE_CHECKS > 1
+                  if (crc == 0)
+                  {
+                     crc = crc32(0, NULL, 0);
+                     crc = crc32(crc, profile, length);
+                  }
+
+                  /* So this check must pass for the 'return' below to happen.
+                   */
+                  if (crc == png_sRGB_checks[i].crc)
+#              endif
+               {
+                  /* Warn that this being done; this isn't even an error since
+                   * the profile is perfectly valid, but it would be nice if
+                   * people used the up-to-date ones.
+                   */
+                  if (!png_sRGB_checks[i].have_md5)
+                  {
+#                    ifdef PNG_READ_SUPPORTED
+                        if (png_ptr->mode & PNG_IS_READ_STRUCT)
+                           png_chunk_warning(png_ptr,
+                              "out-of-date sRGB profile with no signature");
+                        else
+#                    endif
+                     png_app_warning(png_ptr,
+                        "out-of-date sRGB profile with no signature");
+                  }
+
+                  return 1;
+               }
+            }
+         }
+
+#        if PNG_sRGB_PROFILE_CHECKS > 0
+            /* The signature matched, but the profile had been changed in some
+             * way.  This is an apparent violation of the ICC terms of use and,
+             * anyway, the rejection may be unexpected.
+             */
+            if (png_sRGB_checks[i].have_md5)
+               png_benign_error(png_ptr,
+                  "copyright violation: edited ICC profile ignored");
+#        endif
+      }
+   }
+
+   return 0; /* no match */
+}
+#endif
+
+int /* PRIVATE */
 png_icc_set_gAMA_and_cHRM(png_const_structrp png_ptr,
    png_colorspacerp colorspace, png_const_charp name, png_const_bytep profile,
-   int preferred)
+   uLong adler, int preferred)
 {
-   /* TODO: implement this! */
-   PNG_UNUSED(png_ptr)
-   PNG_UNUSED(colorspace)
-   PNG_UNUSED(name)
-   PNG_UNUSED(profile)
-   PNG_UNUSED(preferred)
+#  ifdef PNG_sRGB_SUPPORTED
+      /* 1) Is this profile one of the known ICC sRGB profiles?  If it is just
+       *    set the sRGB information.
+       */
+      if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler))
+         return png_colorspace_set_sRGB(png_ptr, colorspace,
+            (int)/*already checked*/png_get_uint_32(profile+64), preferred);
+
+      else
+#  endif
+
+   /* 2) Attempt to extract the gAMA and cHRM information from non-sRGB
+    *    profiles.
+    */
+   {
+      /* TODO: implement this! */
+      PNG_UNUSED(name) /* NYI */
+      return 1;
+   }
 }
 
 int /* PRIVATE */
@@ -2000,7 +2175,8 @@
       && png_icc_check_tag_table(png_ptr, colorspace, name, profile_length,
          profile))
    {
-      png_icc_set_gAMA_and_cHRM(png_ptr, colorspace, name, profile, preferred);
+      png_icc_set_gAMA_and_cHRM(png_ptr, colorspace, name, profile, 0,
+         preferred);
       return 1;
    }
 
diff --git a/pngpriv.h b/pngpriv.h
index 7a61a2d..71cb28f 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -1443,9 +1443,14 @@
    png_colorspacerp colorspace, png_const_charp name,
    png_uint_32 profile_length,
    png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY);
-PNG_INTERNAL_FUNCTION(void,png_icc_set_gAMA_and_cHRM,(
+PNG_INTERNAL_FUNCTION(int,png_icc_set_gAMA_and_cHRM,(
    png_const_structrp png_ptr, png_colorspacerp colorspace,
-   png_const_charp name, png_const_bytep profile, int preferred), PNG_EMPTY);
+   png_const_charp name, png_const_bytep profile, uLong adler, int preferred),
+   PNG_EMPTY);
+   /* 'adler' is the Adler32 checksum of the uncompressed profile data, it may
+    * be 0 to indicate that it is not available.  It is used, if provided, as a
+    * fast check on the profile when checking to see if it is sRGB.
+    */
 #endif /* iCCP */
 
 #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
diff --git a/pngread.c b/pngread.c
index ef348fa..3996041 100644
--- a/pngread.c
+++ b/pngread.c
@@ -63,7 +63,7 @@
          /* In stable builds only warn if an application error can be completely
           * handled.
           */
-#        if PNG_LIBPNG_BUILD_BASE_TYPE == PNG_LIBPNG_BUILD_STABLE
+#        if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
             png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
 #        endif
 #     endif
diff --git a/pngrutil.c b/pngrutil.c
index b8a3d00..efcac78 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -338,7 +338,7 @@
        * are minimal.
        */
       (void)png_safecat(msg, sizeof msg, 4, " using zstream");
-#     if PNG_LIBPNG_BUILD_BASE_TYPE == PNG_LIBPNG_BUILD_STABLE
+#     if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
          png_chunk_warning(png_ptr, msg);
          png_ptr->zowner = 0;
 #     else
@@ -1314,72 +1314,12 @@
 #endif /* PNG_READ_sRGB_SUPPORTED */
 
 #ifdef PNG_READ_iCCP_SUPPORTED
-#ifdef PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED
-int /* PRIVATE */
-png_compare_ICC_profile_with_sRGB(png_structrp png_ptr, png_bytep profile,
-    png_uint_32 length)
-{
-   /* See if it's a known sRGB profile. If it is, return intent;
-    * if not, return -1.
-    */
-
-   int
-     icheck;
-
-   /* Known sRGB profiles:
-    * 0: not a known sRGB profile
-    * 1: HP-Microsoft sRGB v2 perceptual
-    * 2: ICC sRGB v4 perceptual
-    * 3: ICC sRGB v2 perceptual
-    *    no black-compensation
-    */
-
-   typedef struct png_sRGB_check_struct
-   {
-      uLong crc;
-      uLong adler;
-      png_uint_32 check_len;
-      int intent;
-   } png_sRGB_check;
-
-   png_sRGB_check check[3] =
-   {  
-      { 0xf29e526dUL, 0x0398f3fcUL,   3144UL,    0 },
-      { 0xbbef7812UL, 0x209c35d2UL,  60960UL,    0 },
-      { 0x427ebb21UL, 0x4909e5e1UL,   3052UL,    0 }
-   };
-      
-   if (png_ptr == NULL)
-      return -1;
-
-   for (icheck = 2; icheck >= 0; icheck--)
-   {
-      if (length == check[icheck].check_len)
-      {
-         uLong profile_adler = adler32(1, profile, length);
-
-         if (profile_adler == (uLong) check[icheck].adler)
-         {
-            uLong profile_crc = crc32(0, profile, length);
-
-            if (profile_crc == (uLong) check[icheck].crc)
-               return check[icheck].intent;
-
-            else
-               return -1;
-         }
-      }
-   } 
-
-   return -1;
-}
-#endif
-
 void /* PRIVATE */
 png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle profiles that are > 64K under DOS */
 {
-   png_const_charp errmsg;
+   png_const_charp errmsg = NULL; /* error message output, or no error */
+   int finished = 0; /* crc checked */
 
    png_debug(1, "in png_handle_iCCP");
 
@@ -1452,14 +1392,13 @@
             if (png_inflate_claim(png_ptr, png_iCCP,
                png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK)
             {
-               int ret;
                Byte profile_header[132];
                Byte local_buffer[PNG_INFLATE_BUF_SIZE];
                png_alloc_size_t size = sizeof profile_header;
 
                png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2);
                png_ptr->zstream.avail_in = read_length;
-               ret = png_inflate_read(png_ptr, local_buffer,
+               (void)png_inflate_read(png_ptr, local_buffer,
                   sizeof local_buffer, &length, profile_header, &size,
                   0/*finish: don't, because the output is too small*/);
 
@@ -1470,8 +1409,6 @@
                   const png_uint_32 profile_length =
                      png_get_uint_32(profile_header);
 
-                  errmsg = NULL; /* flag to say error message output */
-
                   if (png_icc_check_length(png_ptr, &png_ptr->colorspace,
                      keyword, profile_length))
                   {
@@ -1498,10 +1435,13 @@
 
                            size = 12 * tag_count;
 
-                           ret = png_inflate_read(png_ptr, local_buffer,
+                           (void)png_inflate_read(png_ptr, local_buffer,
                               sizeof local_buffer, &length,
                               profile + (sizeof profile_header), &size, 0);
 
+                           /* Still expect a a buffer error because we expect
+                            * there to be some tag data!
+                            */
                            if (size == 0)
                            {
                               if (png_icc_check_tag_table(png_ptr,
@@ -1514,53 +1454,43 @@
                                  size = profile_length - (sizeof profile_header)
                                     - 12 * tag_count;
 
-                                 ret = png_inflate_read(png_ptr, local_buffer,
+                                 (void)png_inflate_read(png_ptr, local_buffer,
                                     sizeof local_buffer, &length,
                                     profile + (sizeof profile_header) +
                                     12 * tag_count, &size, 1/*finish*/);
 
-                                 if (size == 0)
+                                 if (length > 0 && !(png_ptr->flags &
+                                       PNG_FLAG_BENIGN_ERRORS_WARN))
+                                    errmsg = "extra compressed data";
+
+                                 /* But otherwise allow extra data: */
+                                 else if (size == 0)
                                  {
-#ifdef PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED
-                                    int
-                                      intent;
-#endif
+                                    int ok;
 
-                                    if (ret != Z_STREAM_END)
-                                       png_chunk_warning(png_ptr,
-                                          png_ptr->zstream.msg);
-
-                                    else if (length > 0)
+                                    if (length > 0)
+                                    {
+                                       /* This can be handled completely, so
+                                        * keep going.
+                                        */
                                        png_chunk_warning(png_ptr,
                                           "extra compressed data");
+                                    }
 
-                                    /* But, because we got the whole profile,
-                                     * assume it is ok.
+                                    png_crc_finish(png_ptr, length);
+                                    finished = 1;
+
+                                    /* Set the gAMA and cHRM information, this
+                                     * checks for a known sRGB profile.  The
+                                     * result is 0 on error.
                                      */
-                                    png_ptr->zowner = 0;
-
-                                    /* Yet the CRC should still be correct */
-                                    if (png_crc_finish(png_ptr, length))
-                                       return;
-
-#ifdef PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED
-                                    /* See if it's a known sRGB profile. */
-                                    intent =
-                                        png_compare_ICC_profile_with_sRGB(
-                                            png_ptr, profile, profile_length);
-
-                                    if (intent >= 0)
-                                       png_chunk_warning(png_ptr,
-                                         "describes sRGB\n");
-#endif
-
-                                    /* Set the gAMA and cHRM information */
-                                    png_icc_set_gAMA_and_cHRM(png_ptr,
+                                    ok = png_icc_set_gAMA_and_cHRM(png_ptr,
                                        &png_ptr->colorspace, keyword, profile,
+                                       png_ptr->zstream.adler,
                                        0/*prefer explicit gAMA/cHRM*/);
 
                                     /* Steal the profile for info_ptr. */
-                                    if (info_ptr != NULL)
+                                    if (ok && info_ptr != NULL)
                                     {
                                        png_free_data(png_ptr, info_ptr,
                                           PNG_FREE_ICCP, 0);
@@ -1568,33 +1498,50 @@
                                        info_ptr->iccp_name = png_voidcast(char*,
                                           png_malloc_base(png_ptr,
                                           keyword_length+1));
-                                       if (info_ptr->iccp_name == NULL)
+                                       if (info_ptr->iccp_name != NULL)
+                                       {
+                                          memcpy(info_ptr->iccp_name, keyword,
+                                             keyword_length+1);
+                                          info_ptr->iccp_proflen =
+                                             profile_length;
+                                          info_ptr->iccp_profile = profile;
+                                          png_ptr->read_buffer = NULL; /*steal*/
+                                          info_ptr->free_me |= PNG_FREE_ICCP;
+                                          info_ptr->valid |= PNG_INFO_iCCP;
+                                       }
+
+                                       else
                                        {
                                           png_ptr->colorspace.flags |=
                                              PNG_COLORSPACE_INVALID;
-                                          png_colorspace_sync(png_ptr,
-                                             info_ptr);
-                                          png_chunk_benign_error(png_ptr,
-                                             "out of memory");
-                                          return;
+                                          errmsg = "out of memory";
                                        }
-
-                                       memcpy(info_ptr->iccp_name, keyword,
-                                          keyword_length+1);
-                                       info_ptr->iccp_proflen = profile_length;
-                                       info_ptr->iccp_profile = profile;
-                                       png_ptr->read_buffer = NULL; /*steal*/
-                                       info_ptr->free_me |= PNG_FREE_ICCP;
-                                       info_ptr->valid |= PNG_INFO_iCCP;
-
-                                       png_colorspace_sync(png_ptr, info_ptr);
                                     }
 
-                                    return;
+                                    /* else the profile remains in the read
+                                     * buffer which gets reused for subsequent
+                                     * chunks.
+                                     */
+
+                                    if (info_ptr != NULL)
+                                       png_colorspace_sync(png_ptr, info_ptr);
+
+                                    if (errmsg == NULL && ok)
+                                    {
+                                       png_ptr->zowner = 0;
+                                       return;
+                                    }
+
+                                    /* else png_icc_set_gAMA_and_cHRM has
+                                     * already output an error.
+                                     */
                                  }
 
-                                 else
+                                 else if (size > 0)
                                     errmsg = "truncated";
+
+                                 else
+                                    errmsg = png_ptr->zstream.msg;
                               }
 
                               /* else png_icc_check_tag_table output an error */
@@ -1637,7 +1584,9 @@
       errmsg = "too many profiles";
 
    /* Failure: the reason is in 'errmsg' */
-   png_crc_finish(png_ptr, length);
+   if (!finished)
+      png_crc_finish(png_ptr, length);
+
    png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID;
    png_colorspace_sync(png_ptr, info_ptr);
    if (errmsg != NULL) /* else already output */
diff --git a/pngwrite.c b/pngwrite.c
index 606ee5e..769da73 100644
--- a/pngwrite.c
+++ b/pngwrite.c
@@ -82,25 +82,32 @@
 #endif
 
 #ifdef PNG_COLORSPACE_SUPPORTED
-   /* Write only one of sRGB or an ICC profile, favour sRGB if the profile
-    * matches sRGB.
+   /* Write only one of sRGB or an ICC profile.  If a profile was supplied
+    * and it matches one of the known sRGB ones issue a warning.
     */
+#  ifdef PNG_WRITE_iCCP_SUPPORTED
+      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
+         (info_ptr->valid & PNG_INFO_iCCP))
+      {
+#        ifdef PNG_WRITE_sRGB_SUPPORTED
+            if (info_ptr->valid & PNG_INFO_sRGB)
+               png_app_warning(png_ptr,
+                  "profile matches sRGB but writing iCCP instead");
+#        endif
+
+         png_write_iCCP(png_ptr, info_ptr->iccp_name,
+            info_ptr->iccp_profile);
+      }
+#     ifdef PNG_WRITE_sRGB_SUPPORTED
+         else
+#     endif
+#  endif
+
 #  ifdef PNG_WRITE_sRGB_SUPPORTED
       if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
          (info_ptr->valid & PNG_INFO_sRGB))
          png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent);
-
-#     ifdef PNG_WRITE_iCCP_SUPPORTED
-         else
-#     endif
 #  endif /* WRITE_sRGB */
-
-#  ifdef PNG_WRITE_iCCP_SUPPORTED
-      if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) &&
-         (info_ptr->valid & PNG_INFO_iCCP))
-         png_write_iCCP(png_ptr, info_ptr->iccp_name,
-            info_ptr->iccp_profile);
-#  endif
 #endif /* COLORSPACE */
 
 #ifdef PNG_WRITE_sBIT_SUPPORTED
@@ -527,6 +534,16 @@
     */
 #  ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED
       png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
+      /* In stable builds only warn if an application error can be completely
+       * handled.
+       */
+#  endif
+
+   /* App warnings are warnings in release (or release candidate) builds but
+    * are errors during development.
+    */
+#  if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
+      png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
 #  endif
 
    if (png_ptr != NULL)
diff --git a/pngwutil.c b/pngwutil.c
index a6a659b..ca745f7 100644
--- a/pngwutil.c
+++ b/pngwutil.c
@@ -325,7 +325,7 @@
        * are minimal.
        */
       (void)png_safecat(msg, sizeof msg, 10, " using zstream");
-#     if PNG_LIBPNG_BUILD_BASE_TYPE == PNG_LIBPNG_BUILD_STABLE
+#     if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
          png_warning(png_ptr, msg);
 
          /* Attempt sane error recovery */
diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa
index 3b77065..7b1cc23 100644
--- a/scripts/pnglibconf.dfa
+++ b/scripts/pnglibconf.dfa
@@ -478,7 +478,46 @@
 option GAMMA disabled
 option COLORSPACE enables GAMMA disabled
 
+# When an ICC profile is read, or png_set, it will be checked for a match
+# against known sRGB profiles if the sRGB handling is enabled.  This
+# setting controls how much work is done during the check:
 #
+# 0: Just validate the profile MD5 signature if present, otherwise use
+#    the checks in option 1.
+#
+# 1: Additionally check the length, intent and adler32 checksum of the
+#    actual data.   If enabled this will reject known profiles that have
+#    had the rendering intent in the header changed as well as other edits
+#    done without updating the checksum.  See the discussion below.
+#
+# 2: Additionally checksum all the data using the ethernet CRC32 algorithm.
+#    This makes it more difficult to fake profiles and makes it less likely
+#    to get a false positive on profiles with no signature, but is probably
+#    just a waste of time since all currently approved ICC sRGB profiles have
+#    a secure MD5 signature.
+#
+# The rendering intent.  An ICC profile stores an intended rendering intent,
+# but does not include the value in the signature.  The intent is documented
+# as the intent that should be used when combining two profiles.  The sRGB
+# profile is intended, however, to be used with any of the four defined intents.
+# For this reason the sRGB chunk includes an 'intent' to be used when displaying
+# the image (intent is really a property of the image not the profile.)
+#
+# Unfortunately the iCCP chunk does not.  It may therefore be that some
+# applications modify the intent in profiles (including sRGB profiles) to work
+# round this problem.  Selecting an option other than option '0' will cause such
+# modified profiles to be rejected.
+#
+# Security.  The use of Adler32 and CRC32 checksums does not help significantly
+# with any security issues.  It is relatively easy to produce arbitrary profiles
+# with the required checksums on current computer systems.  Nevertheless
+# security does not seem to be an issue because the only consequence of a false
+# positive is a false assertion that the profile is an sRGB profile.  This might
+# be used to hide data from libpng using applications, but it doesn't seem
+# possible to damage them.
+
+setting sRGB_PROFILE_CHECKS default 2
+
 # Artificially align memory - the code typically aligns to 8 byte
 # boundaries if this is switched on, it's a small waste of space
 # but can help (in theory) on some architectures.  Only affects
@@ -650,9 +689,6 @@
 option READ_CHECK_FOR_INVALID_INDEX requires READ CHECK_FOR_INVALID_INDEX
 option WRITE_CHECK_FOR_INVALID_INDEX requires WRITE CHECK_FOR_INVALID_INDEX
 
-# added at libpng-1.6.0
-option WARN_IF_iCCP_IS_sRGB requires READ iCCP
-
 # Simplified API options (added at libpng-1.6.0)
 # Read:
 option SIMPLIFIED_READ requires SEQUENTIAL_READ READ_TRANSFORMS SETJMP
diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt
index e368b50..14452e2 100644
--- a/scripts/pnglibconf.h.prebuilt
+++ b/scripts/pnglibconf.h.prebuilt
@@ -3,7 +3,7 @@
 
 /* pnglibconf.h - library build configuration */
 
-/* Libpng 1.6.0beta20 - March 28, 2012 */
+/* Libpng 1.6.0beta20 - March 29, 2012 */
 
 /* Copyright (c) 1998-2012 Glenn Randers-Pehrson */
 
@@ -33,6 +33,7 @@
 #define PNG_QUANTIZE_GREEN_BITS 5
 #define PNG_QUANTIZE_RED_BITS 5
 #define PNG_sCAL_PRECISION 5
+#define PNG_sRGB_PROFILE_CHECKS 2
 #define PNG_WEIGHT_SHIFT 8
 #define PNG_ZBUF_SIZE 8192
 /* end of settings */
@@ -138,7 +139,6 @@
 #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
 #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
 #define PNG_SIMPLIFIED_WRITE_SUPPORTED
-#define PNG_WARN_IF_iCCP_IS_sRGB_SUPPORTED
 #define PNG_sPLT_SUPPORTED
 #define PNG_sRGB_SUPPORTED
 #define PNG_STDIO_SUPPORTED