[libpng17] Port recent zlib windowBits handling from libpng-1.6.3beta06
diff --git a/ANNOUNCE b/ANNOUNCE
index 3f02f3e..3e24450 100644
--- a/ANNOUNCE
+++ b/ANNOUNCE
@@ -285,6 +285,23 @@
     Added a call to png_set_packing()
     Initialize dimension values so if sscanf fails at least we have known
       invalid values.
+  Calculate our own zlib windowBits when decoding rather than trusting the
+    CMF bytes in the PNG datastream.
+  Added an option to force maximum window size for inflating, which was
+    the behavior of libpng15 and earlier.
+  Added png-fix-itxt and png-fix-too-far-back to the built programs and
+    removed warnings from the source code and timepng that are revealed as
+    a result.
+  Detect wrong libpng versions linked to png-fix-too-far-back, which currently
+    only works with libpng versions that can be made to reliably fail when
+    the deflate data contains an out-of-window reference.  This means only
+    1.6 and later.
+  Attempt to detect configuration issues with png-fix-too-far-back, which
+    requires both the correct libpng and the correct zlib to function
+    correctly.
+  Check ZLIB_VERNUM for mismatches, enclose #error in quotes
+  Added information in the documentation about problems with and fixes for
+    the bad CRC and bad iTXt chunk situations.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/CHANGES b/CHANGES
index 80cc136..daac046 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4573,6 +4573,23 @@
     Added a call to png_set_packing()
     Initialize dimension values so if sscanf fails at least we have known
       invalid values.
+  Calculate our own zlib windowBits when decoding rather than trusting the
+    CMF bytes in the PNG datastream.
+  Added an option to force maximum window size for inflating, which was
+    the behavior of libpng15 and earlier.
+  Added png-fix-itxt and png-fix-too-far-back to the built programs and
+    removed warnings from the source code and timepng that are revealed as
+    a result.
+  Detect wrong libpng versions linked to png-fix-too-far-back, which currently
+    only works with libpng versions that can be made to reliably fail when
+    the deflate data contains an out-of-window reference.  This means only
+    1.6 and later.
+  Attempt to detect configuration issues with png-fix-too-far-back, which
+    requires both the correct libpng and the correct zlib to function
+    correctly.
+  Check ZLIB_VERNUM for mismatches, enclose #error in quotes
+  Added information in the documentation about problems with and fixes for
+    the bad CRC and bad iTXt chunk situations.
 
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
 (subscription required; visit
diff --git a/LICENSE b/LICENSE
index 5969dac..9514e7f 100644
--- a/LICENSE
+++ b/LICENSE
@@ -10,7 +10,7 @@
 
 This code is released under the libpng license.
 
-libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are
+libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are
 Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are
 distributed according to the same disclaimer and license as libpng-1.2.5
 with the following individual added to the list of Contributing Authors
@@ -108,4 +108,4 @@
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-April 30, 2013
+May 10, 2013
diff --git a/Makefile.am b/Makefile.am
index 006cb93..c51ee4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,6 +9,9 @@
 # test programs - run on make check, make distcheck
 check_PROGRAMS= pngtest pngunknown pngstest pngvalid
 
+# Utilities - installed
+bin_PROGRAMS= png-fix-too-far-back png-fix-itxt
+
 pngtest_SOURCES = pngtest.c
 pngtest_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 
@@ -21,6 +24,11 @@
 pngunknown_SOURCES = contrib/libtests/pngunknown.c
 pngunknown_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
 
+png_fix_too_far_back_SOURCES = contrib/tools/png-fix-too-far-back.c
+png_fix_too_far_back_LDADD = libpng@PNGLIB_MAJOR@@PNGLIB_MINOR@.la
+
+png_fix_itxt_SOURCES = contrib/tools/png-fix-itxt.c
+
 # Generally these are single line shell scripts to run a test with a particular
 # set of parameters:
 TESTS =\
@@ -182,14 +190,15 @@
 $(srcdir)/scripts/pnglibconf.h.prebuilt:
 	@echo "Attempting to build $@" >&2
 	@echo "This is a machine generated file, but if you want to make" >&2
-	@echo "a new one simply make 'scripts/pnglibconf.out' and copy that" >&2
+	@echo "a new one simply make 'scripts/pnglibconf.out', copy that" >&2
+	@echo "AND set PNG_ZLIB_VERNUM to 0 (you MUST do this)" >&2
 	@exit 1
 
 # The following is necessary to ensure that the local pnglibconf.h is used, not
 # an installed one (this can happen immediately after on a clean system if
 # 'make test' is the first thing the user does.)
-contrib/libtests/pngstest.o contrib/libtests/pngvalid.o pngtest.o: pnglibconf.h
-contrib/libtests/pngunknown.o: pnglibconf.h
+pngstest.o pngvalid.o pngtest.o pngunknown.o timepng.o: pnglibconf.h
+png-fix-too-far-back.o png-fix-itxt.o: pnglibconf.h
 
 # We must use -DPNG_NO_USE_READ_MACROS here even when the library may actually
 # be built with PNG_USE_READ_MACROS; this prevents the read macros from
diff --git a/README b/README
index c5f2133..19d755a 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-README for libpng version 1.7.0beta13 - April 30, 2013 (shared library 17.0)
+README for libpng version 1.7.0beta13 - May 10, 2013 (shared library 17.0)
 See the note about version numbers near the top of png.h
 
 See INSTALL for instructions on how to install libpng.
diff --git a/contrib/tools/png-fix-itxt.c b/contrib/tools/png-fix-itxt.c
new file mode 100644
index 0000000..7cbd996
--- /dev/null
+++ b/contrib/tools/png-fix-itxt.c
@@ -0,0 +1,153 @@
+
+/* png-fix-itxt version 1.0.0
+ *
+ * Copyright 2013 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.3 [(PENDING RELEASE)]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * Usage:            
+ *
+ *     png-fix-itxt.exe < bad.png > good.png
+ *
+ * Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more
+ * uncompressed iTXt chunks.  Assumes that the actual length is greater
+ * than or equal to the value in the length byte, and that the CRC is
+ * correct for the actual length.  This program hunts for the CRC and
+ * adjusts the length byte accordingly.  It is not an error to process a
+ * PNG file that has no iTXt chunks or one that has valid iTXt chunks;
+ * such files will simply be copied.
+ *
+ * Requires zlib (for crc32 and Z_NULL); build with
+ *
+ *     gcc -O -o png-fix-itxt png-fix-itxt.c -lz
+ *
+ * If you need to handle iTXt chunks larger than 500000 kbytes you must
+ * rebuild png-fix-itxt with a larger values of MAX_LENGTH (or a smaller value
+ * if you know you will never encounter such huge iTXt chunks).
+ */
+
+#include <stdio.h>
+#include <zlib.h>
+
+#define MAX_LENGTH 500000
+
+#define GETBREAK ((unsigned char)(inchar=getchar())); if (inchar == EOF) break
+
+int
+main(void)
+{
+   unsigned int i;
+   unsigned char buf[MAX_LENGTH];
+   unsigned long crc;
+   unsigned char c;
+   int inchar;
+
+/* Skip 8-byte signature */
+   for (i=8; i; i--)
+   {
+      c=GETBREAK;
+      putchar(c);
+   }
+
+if (inchar != EOF)
+for (;;)
+ {
+   /* Read the length */
+   unsigned long length; /* must be 32 bits! */
+   c=GETBREAK; buf[0] = c; length  = c; length <<= 8;
+   c=GETBREAK; buf[1] = c; length += c; length <<= 8;
+   c=GETBREAK; buf[2] = c; length += c; length <<= 8;
+   c=GETBREAK; buf[3] = c; length += c;
+
+   /* Read the chunkname */
+   c=GETBREAK; buf[4] = c;
+   c=GETBREAK; buf[5] = c;
+   c=GETBREAK; buf[6] = c;
+   c=GETBREAK; buf[7] = c;
+
+
+   /* The iTXt chunk type expressed as integers is (105, 84, 88, 116) */
+   if (buf[4] == 105 && buf[5] == 84 && buf[6] == 88 && buf[7] == 116)
+   {
+      if (length >= MAX_LENGTH-12)
+         break;  /* To do: handle this more gracefully */
+
+      /* Initialize the CRC */
+      crc = crc32(0, Z_NULL, 0);
+
+      /* Copy the data bytes */
+      for (i=8; i < length + 12; i++)
+      {
+         c=GETBREAK; buf[i] = c;
+      }
+
+      /* Calculate the CRC */
+      crc = crc32(crc, buf+4, (uInt)length+4);
+
+      for (;;)
+      {
+        /* Check the CRC */
+        if (((crc >> 24) & 0xff) == buf[length+8] &&
+            ((crc >> 16) & 0xff) == buf[length+9] &&
+            ((crc >>  8) & 0xff) == buf[length+10] &&
+            ((crc      ) & 0xff) == buf[length+11])
+           break;
+
+        length++;
+
+        if (length >= MAX_LENGTH-12)
+           break;
+
+        c=GETBREAK;
+        buf[length+11]=c;
+
+        /* Update the CRC */
+        crc = crc32(crc, buf+7+length, 1);
+      }
+
+      /* Update length bytes */
+        buf[0] = (length << 24) & 0xff;
+        buf[1] = (length << 16) & 0xff;
+        buf[2] = (length <<  8) & 0xff;
+        buf[3] = (length      ) & 0xff;
+
+      /* Write the fixed iTXt chunk (length, name, data, crc) */
+      for (i=0; i<length+12; i++)
+         putchar(buf[i]);
+   }
+
+   else
+   {
+      /* Copy bytes that were already read (length and chunk name) */
+      for (i=0; i<8; i++)
+         putchar(buf[i]);
+
+      /* Copy data bytes and CRC */
+      for (i=8; i< length+12; i++)
+      {
+         c=GETBREAK;
+         putchar(c);
+      }
+
+      if (inchar == EOF)
+      {
+         break;
+      }
+
+   /* The IEND chunk type expressed as integers is (73, 69, 78, 68) */
+      if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
+         break;
+   }
+
+   if (inchar == EOF)
+      break;
+
+   if (buf[4] == 73 && buf[5] == 69 && buf[6] == 78 && buf[7] == 68)
+     break;
+ }
+
+ return 0;
+}
diff --git a/contrib/tools/png-fix-too-far-back.c b/contrib/tools/png-fix-too-far-back.c
new file mode 100644
index 0000000..829253a
--- /dev/null
+++ b/contrib/tools/png-fix-too-far-back.c
@@ -0,0 +1,1263 @@
+/* png-fix-too-far-back.c
+ *
+ * Copyright (c) 2013 John Cunningham Bowler
+ *
+ * Last changed in libpng 1.6.3 [(PENDING RELEASE)]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ *
+ * Tool to check and fix the zlib inflate 'too far back' problem, see the usage
+ * message for more information.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define PROGRAM_NAME "png-fix-too-far-back"
+
+/* Define the following to use this program against your installed libpng,
+ * rather than the one being built here:
+ */
+#ifdef PNG_FREESTANDING_TESTS
+#  include <png.h>
+#else
+#  include "../../png.h"
+#endif
+
+#if PNG_LIBPNG_VER < 10603 /* 1.6.3 */
+#  error "png-fix-too-far-back will not work with libpng prior to 1.6.3"
+#endif
+
+#ifdef PNG_READ_SUPPORTED
+#include <zlib.h>
+
+#ifndef PNG_MAXIMUM_INFLATE_WINDOW
+#  error "png-fix-too-far-back not supported in this libpng version"
+#endif
+
+#if PNG_ZLIB_VERNUM >= 0x1240
+
+/* Copied from pngpriv.h */
+#ifdef __cplusplus
+#  define png_voidcast(type, value) static_cast<type>(value)
+#  define png_constcast(type, value) const_cast<type>(value)
+#  define png_aligncast(type, value) \
+   static_cast<type>(static_cast<void*>(value))
+#  define png_aligncastconst(type, value) \
+   static_cast<type>(static_cast<const void*>(value))
+#else
+#  define png_voidcast(type, value) (value)
+#  define png_constcast(type, value) ((type)(value))
+#  define png_aligncast(type, value) ((void*)(value))
+#  define png_aligncastconst(type, value) ((const void*)(value))
+#endif /* __cplusplus */
+
+static int idat_error = 0;
+static int verbose = 0;
+static int errors = 0;
+static int warnings = 0;
+#ifdef PNG_MAXIMUM_INFLATE_WINDOW
+   static int set_option = 0;
+#endif
+static const char *name = "stdin";
+static uLong crc_IDAT_head; /* CRC32 of "IDAT" */
+static uLong crc_IEND;
+static z_stream z_idat;
+
+/* Control structure for the temporary file */
+typedef struct
+{
+   size_t      image_size;
+   off_t       file_size;
+   fpos_t      header_pos;
+   fpos_t      crc_pos;
+   uLong       crc_tail;  /* CRC of bytes after header */
+   png_uint_32 len_tail;  /* Count thereof */
+   png_byte    header[2];
+
+   /* Image info */
+   png_uint_32 width;
+   png_uint_32 height;
+   png_byte    bit_depth;
+   png_byte    color_type;
+   png_byte    compression_method;
+   png_byte    filter_method;
+   png_byte    interlace_method;
+} IDAT_info;
+
+static png_uint_32
+mult(png_uint_32 n, png_uint_32 m)
+{
+   if ((n + (m-1)) / m > 0xffffffff/m)
+   {
+      fprintf(stderr, "%s: overflow (%lu, %u)\n", name, (unsigned long)n, m);
+      exit(2);
+   }
+
+   return n * m;
+}
+
+static size_t
+image_size(const IDAT_info *info)
+{
+   unsigned int pd = info->bit_depth;
+   size_t cb;
+
+   switch (info->color_type)
+   {
+      case 0: case 3:
+         break;
+
+      case 2: /* rgb */
+         pd *= 3;
+         break;
+
+      case 4: /* ga */
+         pd *= 2;
+         break;
+
+      case 6: /* rgba */
+         pd *= 4;
+         break;
+
+      default:
+         fprintf(stderr, "%s: invalid color type (%d)\n", name,
+            info->color_type);
+         exit(2);
+   }
+
+   switch (info->interlace_method)
+   {
+      case PNG_INTERLACE_ADAM7:
+         /* Interlacing makes the image larger because of the replication of
+          * both the filter byte and the padding to a byte boundary.
+          */
+         {
+            int pass;
+
+            for (cb=0, pass=0; pass<=6; ++pass)
+            {
+               png_uint_32 pw = PNG_PASS_COLS(info->width, pass);
+
+               if (pw > 0)
+                  cb += mult(((mult(pd, pw)+7) >> 3)+1,
+                        PNG_PASS_ROWS(info->height, pass));
+            }
+         }
+         break;
+
+      case PNG_INTERLACE_NONE:
+         cb = mult(info->height, 1+((mult(info->width, pd) + 7) >> 3));
+         break;
+
+      default:
+         fprintf(stderr, "%s: invalid interlace type %d\n", name,
+            info->interlace_method);
+         exit(2);
+   }
+
+   return cb;
+}
+
+static int
+image_windowBits(const IDAT_info *info)
+{
+   size_t cb = image_size(info);
+
+   if (cb > 16384) return 15;
+   if (cb >  8192) return 14;
+   if (cb >  4096) return 13;
+   if (cb >  2048) return 12;
+   if (cb >  1024) return 11;
+   if (cb >   512) return 10;
+   if (cb >   256) return  9;
+   return 8;
+}
+
+static void
+error_handler(png_structp png_ptr, png_const_charp message)
+{
+   if (strcmp(message, "IDAT: invalid distance too far back") == 0)
+      idat_error = 1;
+
+   else if (errors || verbose)
+      fprintf(stderr, "%s: %s\n", name, message);
+
+   png_longjmp(png_ptr, 1);
+}
+
+static void
+warning_handler(png_structp png_ptr, png_const_charp message)
+{
+   if (warnings || verbose)
+      fprintf(stderr, "%s: %s\n", name, message);
+
+   (void)png_ptr;
+}
+
+static int
+read_png(FILE *fp)
+{
+   png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,
+      error_handler, warning_handler);
+   png_infop info_ptr = NULL;
+   png_bytep row = NULL, display = NULL;
+
+   if (png_ptr == NULL)
+      return 0;
+
+   if (setjmp(png_jmpbuf(png_ptr)))
+   {
+      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+      if (row != NULL) free(row);
+      if (display != NULL) free(display);
+      return 0;
+   }
+
+#  ifdef PNG_MAXIMUM_INFLATE_WINDOW
+      png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, set_option != 0);
+#  endif
+
+   png_init_io(png_ptr, fp);
+
+   info_ptr = png_create_info_struct(png_ptr);
+   if (info_ptr == NULL)
+      png_error(png_ptr, "OOM allocating info structure");
+
+   png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
+
+   png_read_info(png_ptr, info_ptr);
+
+   /* Limit the decompression buffer size to 1 - this ensures that overlong
+    * length codes are always detected.
+    */
+   png_set_compression_buffer_size(png_ptr, 1);
+
+   {
+      png_size_t rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+      row = png_voidcast(png_byte*, malloc(rowbytes));
+      display = png_voidcast(png_byte*, malloc(rowbytes));
+
+      if (row == NULL || display == NULL)
+         png_error(png_ptr, "OOM allocating row buffers");
+
+      {
+         png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
+         int passes = png_set_interlace_handling(png_ptr);
+         int pass;
+
+         png_start_read_image(png_ptr);
+
+         for (pass = 0; pass < passes; ++pass)
+         {
+            png_uint_32 y = height;
+
+            /* NOTE: this trashes the row each time; interlace handling won't
+             * work, but this avoids memory thrashing for speed testing.
+             */
+            while (y-- > 0)
+               png_read_row(png_ptr, row, display);
+         }
+      }
+   }
+
+   /* Make sure to read to the end of the file: */
+   png_read_end(png_ptr, info_ptr);
+   png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
+   free(row);
+   free(display);
+   return 1;
+}
+
+/* Chunk tags (copied from pngpriv.h) */
+#define PNG_32b(b,s) ((png_uint_32)(b) << (s))
+#define PNG_CHUNK(b1,b2,b3,b4) \
+   (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0))
+
+#if PNG_LIBPNG_VER < 10700 /* These were moved to png.h in 1.7.0 */
+#define png_IHDR PNG_CHUNK( 73,  72,  68,  82)
+#define png_IDAT PNG_CHUNK( 73,  68,  65,  84)
+#define png_IEND PNG_CHUNK( 73,  69,  78,  68)
+#define png_PLTE PNG_CHUNK( 80,  76,  84,  69)
+#define png_bKGD PNG_CHUNK( 98,  75,  71,  68)
+#define png_cHRM PNG_CHUNK( 99,  72,  82,  77)
+#define png_gAMA PNG_CHUNK(103,  65,  77,  65)
+#define png_hIST PNG_CHUNK(104,  73,  83,  84)
+#define png_iCCP PNG_CHUNK(105,  67,  67,  80)
+#define png_iTXt PNG_CHUNK(105,  84,  88, 116)
+#define png_oFFs PNG_CHUNK(111,  70,  70, 115)
+#define png_pCAL PNG_CHUNK(112,  67,  65,  76)
+#define png_sCAL PNG_CHUNK(115,  67,  65,  76)
+#define png_pHYs PNG_CHUNK(112,  72,  89, 115)
+#define png_sBIT PNG_CHUNK(115,  66,  73,  84)
+#define png_sPLT PNG_CHUNK(115,  80,  76,  84)
+#define png_sRGB PNG_CHUNK(115,  82,  71,  66)
+#define png_sTER PNG_CHUNK(115,  84,  69,  82)
+#define png_tEXt PNG_CHUNK(116,  69,  88, 116)
+#define png_tIME PNG_CHUNK(116,  73,  77,  69)
+#define png_tRNS PNG_CHUNK(116,  82,  78,  83)
+#define png_zTXt PNG_CHUNK(122,  84,  88, 116)
+#endif
+
+static void
+rx(FILE *fp, png_bytep buf, off_t cb)
+{
+   if (fread(buf,cb,1,fp) != 1) {
+      fprintf(stderr, "%s: failed to read %lu bytes\n", name,
+         (unsigned long)cb);
+      exit(2);
+   }
+}
+
+static png_uint_32
+r32(FILE *fp)
+{
+   png_byte buf[4];
+   rx(fp, buf, 4);
+   return ((((((png_uint_32)buf[0] << 8)+buf[1]) << 8)+buf[2]) << 8) + buf[3];
+}
+
+static void
+wx(FILE *fp, png_const_bytep buf, off_t cb)
+{
+   if (fwrite(buf,cb,1,fp) != 1) {
+      fprintf(stderr, "%s: failed to write %lu bytes\n", name,
+         (unsigned long)cb);
+      exit(3);
+   }
+}
+
+static void
+w32(FILE *fp, png_uint_32 val)
+{
+   png_byte buf[4];
+   buf[0] = (png_byte)(val >> 24);
+   buf[1] = (png_byte)(val >> 16);
+   buf[2] = (png_byte)(val >>  8);
+   buf[3] = (png_byte)(val);
+   wx(fp, buf, 4);
+}
+
+static void
+wcrc(FILE *fp, uLong crc)
+{
+   /* Safe cast because a CRC is 32 bits */
+   w32(fp, (png_uint_32)crc);
+}
+
+static void
+copy(FILE *fp, FILE *fpIn, off_t cb)
+{
+   png_byte buffer[1024];
+
+   while (cb >= 1024)
+   {
+      rx(fpIn, buffer, 1024);
+      wx(fp, buffer, 1024);
+      cb -= 1024;
+   }
+
+   if (cb > 0)
+   {
+      rx(fpIn, buffer, cb);
+      wx(fp, buffer, cb);
+   }
+}
+
+static void
+skip_bytes(FILE *fpIn, png_uint_32 cb)
+{
+   png_byte buffer[1024];
+
+   while (cb >= 1024)
+   {
+      rx(fpIn, buffer, 1024);
+      cb -= 1024;
+   }
+
+   if (cb > 0)
+      rx(fpIn, buffer, cb);
+}
+
+static void
+safe_getpos(FILE *fp, fpos_t *pos)
+{
+   if (fgetpos(fp, pos))
+   {
+      perror("tmpfile");
+      fprintf(stderr, "%s: tmpfile fgetpos failed\n", name);
+      exit(3);
+   }
+}
+
+static void
+safe_setpos(FILE *fp, fpos_t *pos)
+{
+   if (fflush(fp))
+   {
+      perror("tmpfile");
+      fprintf(stderr, "%s: tmpfile fflush failed\n", name);
+      exit(3);
+   }
+
+   if (fsetpos(fp, pos))
+   {
+      perror("tmpfile");
+      fprintf(stderr, "%s: tmpfile fsetpos failed\n", name);
+      exit(3);
+   }
+}
+
+static void
+idat_update(FILE *fp, IDAT_info *info)
+{
+   uLong crc;
+
+   safe_setpos(fp, &info->header_pos);
+   wx(fp, info->header, 2);
+
+   crc = crc32(crc_IDAT_head, info->header, 2);
+   crc = crc32_combine(crc, info->crc_tail, info->len_tail);
+
+   safe_setpos(fp, &info->crc_pos);
+   wcrc(fp, crc);
+}
+
+static void
+set_bits(const char *file, FILE *fp, IDAT_info *info, int bits)
+{
+   int byte1 = (info->header[0] & 0xf) + ((bits-8) << 4);
+   int byte2 = info->header[1] & 0xe0;
+
+   /* The checksum calculation: */
+   byte2 += 0x1f - ((byte1 << 8) + byte2) % 0x1f;
+
+   info->header[0] = (png_byte)byte1;
+   info->header[1] = (png_byte)byte2;
+
+   if (verbose)
+      fprintf(stderr, "%s: trying windowBits %d (Z_CMF = 0x%x)\n", file, bits,
+         byte1);
+
+   idat_update(fp, info);
+}
+
+static void
+ptagchar(png_uint_32 ch)
+{
+ ch &= 0xff;
+ if (isprint(ch))
+    putc(ch, stderr);
+
+ else
+    fprintf(stderr, "[%02x]", ch);
+}
+
+static void
+ptag(png_uint_32 tag)
+{
+   if (tag != 0)
+   {
+      ptag(tag >> 8);
+      ptagchar(tag);
+   }
+}
+
+static int
+fix_one(FILE *fp, FILE *fpIn, IDAT_info *info, png_uint_32 max_IDAT, int strip)
+{
+   int state = 0;
+      /*   0: at beginning, before first IDAT
+       *   1: read first CMF header byte
+       *   2: read second byte, in first IDAT
+       *   3: after first IDAT
+       *  +4: saw deflate stream end.
+       */
+   int         truncated_idat = 0; /* Count of spurious IDAT bytes */
+   uLong       crc_idat = 0;       /* Running CRC of current IDAT */
+   png_uint_32 len_IDAT = 0;       /* Length of current IDAT */
+   fpos_t      pos_IDAT_length;    /* fpos_t of length field in current IDAT */
+
+   /* The signature: */
+   {
+      png_byte buf[8];
+      rx(fpIn, buf, 8);
+      wx(fp, buf, 8);
+   }
+
+   info->file_size = 45; /* signature + IHDR + IEND */
+
+   for (;;) /* Chunk for loop */
+   {
+      png_uint_32 len = r32(fpIn);
+      png_uint_32 tag = r32(fpIn);
+
+      if (tag == png_IHDR)
+      {
+         /* Need width, height, color type, bit depth and interlace for the
+          * file.
+          */
+         info->width = r32(fpIn);
+         info->height = r32(fpIn);
+         rx(fpIn, &info->bit_depth, 1);
+         rx(fpIn, &info->color_type, 1);
+         rx(fpIn, &info->compression_method, 1);
+         rx(fpIn, &info->filter_method, 1);
+         rx(fpIn, &info->interlace_method, 1);
+
+         /* And write the information. */
+         w32(fp, len);
+         w32(fp, tag);
+         w32(fp, info->width);
+         w32(fp, info->height);
+         wx(fp, &info->bit_depth, 1);
+         wx(fp, &info->color_type, 1);
+         wx(fp, &info->compression_method, 1);
+         wx(fp, &info->filter_method, 1);
+         wx(fp, &info->interlace_method, 1);
+
+         /* Copy the CRC */
+         copy(fp, fpIn, 4);
+      }
+
+      else if (tag == png_IEND)
+      {
+         /* Ok, write an IEND chunk and finish. */
+         w32(fp, 0);
+         w32(fp, png_IEND);
+         wcrc(fp, crc_IEND);
+         break;
+      }
+
+      else if (tag == png_IDAT && len > 0)
+      {
+         /* Write the chunk header now if it hasn't been written yet */
+         if (len_IDAT == 0)
+         {
+            /* The length is set at the end: */
+            safe_getpos(fp, &pos_IDAT_length);
+            w32(fp, max_IDAT); /* length, not yet written */
+            w32(fp, png_IDAT);
+
+            if (state == 0) /* Start of first IDAT */
+            {
+               safe_getpos(fp, &info->header_pos);
+               /* This will become info->crc_tail: */
+               crc_idat = crc32(0L, Z_NULL, 0);
+            }
+
+            else
+               crc_idat = crc_IDAT_head;
+         }
+
+         /* Do the zlib 2-byte header, it gets written out but not added
+          * to the CRC (yet):
+          */
+         while (len > 0 && state < 2)
+         {
+            rx(fpIn, info->header + state, 1);
+            wx(fp, info->header + state, 1);
+            ++len_IDAT;
+            --len;
+
+            if (state++ == 1)
+            {
+               /* The zlib stream is used to validate the compressed IDAT
+                * data in the most relaxed way possible.
+                */
+               png_byte bdummy;
+               int ret;
+
+               z_idat.next_in = info->header;
+               z_idat.avail_in = 2;
+               z_idat.next_out = &bdummy; /* Else Z_STREAM_ERROR! */
+               z_idat.avail_out = 0;
+
+               ret = inflate(&z_idat, Z_NO_FLUSH);
+               if (ret != Z_OK || z_idat.avail_in != 0)
+               {
+                  fprintf(stderr,
+                     "%s: unexpected/invalid inflate result %d \"%s\"\n",
+                     name, ret, z_idat.msg);
+                  return 1;
+               }
+            }
+         } /* while in zlib header */
+
+         /* Process further bytes in the IDAT chunk */
+         while (len > 0 && state < 4)
+         {
+            png_byte b;
+
+            rx(fpIn, &b, 1);
+            --len;
+
+            /* Do this 1 byte at a time to guarantee
+             * detecting errors (in particular zlib can skip the
+             * 'too-far-back' error if the output buffer is bigger than
+             * the window size.)
+             */
+            z_idat.next_in = &b;
+            z_idat.avail_in = 1;
+
+            do
+            {
+               int ret;
+               png_byte bout;
+
+               z_idat.next_out = &bout;
+               z_idat.avail_out = 1;
+
+               ret = inflate(&z_idat, Z_SYNC_FLUSH);
+
+               if (z_idat.avail_out == 0)
+                  ++info->image_size;
+
+               switch (ret)
+               {
+                  case Z_OK:
+                     /* Just keep going */
+                     break;
+
+                  case Z_BUF_ERROR:
+                     if (z_idat.avail_in > 0)
+                     {
+                        fprintf(stderr,
+                           "%s: unexpected buffer error \"%s\"\n",
+                           name, z_idat.msg);
+                        return 1;
+                     }
+                     goto end_loop;
+
+                  case Z_STREAM_END:
+                     /* End of stream */
+                     state |= 4;
+                     goto end_loop;
+
+                  default:
+                     fprintf(stderr, "%s: bad zlib stream %d, \"%s\"\n",
+                        name, ret, z_idat.msg);
+                     return 1;
+               }
+            } while (z_idat.avail_in > 0 || z_idat.avail_out == 0);
+
+            /* The byte need not be consumed, if, for example, there is a
+             * spurious byte after the end of the zlib data.
+             */
+         end_loop:
+            if (z_idat.avail_in == 0)
+            {
+               /* Write it and update the length information and running
+                * CRC.
+                */
+               wx(fp, &b, 1);
+               crc_idat = crc32(crc_idat, &b, 1);
+               ++len_IDAT;
+            }
+
+            else
+               ++truncated_idat;
+
+            if (len_IDAT >= max_IDAT || state >= 4)
+            {
+               /* Either the IDAT chunk is full or we've seen the end of
+                * the deflate stream, or both.  Flush the chunk and handle
+                * the details of the first chunk.
+                */
+               fpos_t save;
+
+               if ((state & 3) < 3) /* First IDAT */
+               {
+                  safe_getpos(fp, &info->crc_pos);
+                  info->crc_tail = crc_idat;
+                  info->len_tail = len_IDAT-2;
+               }
+
+               /* This is not the correct value for the first IDAT! */
+               wcrc(fp, crc_idat);
+               state |= 3;
+
+               /* Update the length if it is not max_IDAT: */
+               if (len_IDAT != max_IDAT)
+               {
+                  safe_getpos(fp, &save);
+                  safe_setpos(fp, &pos_IDAT_length);
+                  w32(fp, len_IDAT);
+                  safe_setpos(fp, &save);
+               }
+
+               /* Add this IDAT to the file size: */
+               info->file_size += 12 + len_IDAT;
+            }
+         } /* while len > 0 && state < 4 */
+
+         /* The above loop only exits on 0 bytes left or end of stream. If
+          * the stream ended with bytes left, discard them:
+          */
+         if (len > 0)
+         {
+            truncated_idat += len;
+            /* Skip those bytes and the CRC */
+            skip_bytes(fpIn, len+4);
+         }
+
+         else
+            skip_bytes(fpIn, 4); /* The CRC */
+      } /* IDAT and len > 0 */
+
+      else
+      {
+         int skip = 0;
+
+         if (tag == png_IDAT)
+            skip = 1;
+
+         else if (state == 0)
+         {
+            /* Chunk before IDAT */
+            if (!skip) switch (strip)
+            {
+               case 0: /* Don't strip */
+                  break;
+
+               case 1:  /* Keep gAMA, sRGB */
+                  if (tag == png_gAMA || tag == png_sRGB)
+                     break;
+                  /* Fall through */
+
+               default: /* Keep only IHDR, PLTE, tRNS */
+                  if (tag == png_IHDR || tag == png_PLTE || tag == png_tRNS)
+                     break;
+
+                  skip = 1;
+                  break;
+            }
+         }
+
+         else if (state >= 4)
+         {
+            /* Keep nothing after IDAT if stripping: */
+            skip = strip;
+         }
+
+         else
+         {
+            /* This is either an unterminated deflate stream or a spurious
+             * non-IDAT chunk in the list of IDAT chunks.  Both are fatal
+             * errors.
+             */
+            fprintf(stderr, "%s: tag '", name);
+            ptag(tag);
+            fprintf(stderr, "' after unterminated IDAT\n");
+            break;
+         }
+
+         /* Skip or send? */
+         if (skip)
+         {
+            if (tag != png_IDAT && (tag & 0x20000000) == 0)
+            {
+               fprintf(stderr, "%s: unknown critical chunk '", name);
+               ptag(tag);
+               fprintf(stderr, "'\n");
+               return 1;
+            }
+
+            /* Skip this tag */
+            if (fseek(fpIn, len+4, SEEK_CUR))
+            {
+               perror(name);
+               fprintf(stderr, "%s: seek failed\n", name);
+               return 1;
+            }
+         }
+
+         else /* Keep this tag */
+         {
+            w32(fp, len);
+            w32(fp, tag);
+            copy(fp, fpIn, len+4);
+            info->file_size += 12+len;
+         }
+      } /* Not IDAT or len == 0 */
+   } /* Chunk for loop */
+
+   /* Break out of the loop on error or end */
+   if (state >= 4)
+   {
+      if (truncated_idat)
+         fprintf(stderr, "%s: removed %d bytes from end of IDAT\n", name,
+            truncated_idat);
+
+      return 0; /* success */
+   }
+
+   /* This is somewhat generic but it works: */
+   fprintf(stderr, "%s: unterminated/truncated PNG (%d)\n", name, state);
+
+   return 1;
+}
+
+static FILE *fpIn;
+
+static int
+fix_file(FILE *fp, const char *file, png_uint_32 max_IDAT, int inplace,
+   int strip, int optimize, const char *output)
+{
+   IDAT_info info;
+   int imageBits, oldBits, bestBits, lowBits, newBits, ok_read;
+
+   memset(&info, 0, sizeof info);
+
+   name = file;
+   idat_error = 0;
+
+   /* fpIn is closed by the caller if necessary */
+   fpIn = fopen(file, "rb");
+   if (fpIn == NULL)
+   {
+      perror(file);
+      fprintf(stderr, "%s: open failed\n", file);
+      return 1;
+   }
+
+   /* With no arguments just check this file */
+   if (optimize == 0 && strip == 0 && inplace == 0 && output == NULL)
+      return !read_png(fpIn);
+
+   /* Otherwise, maybe, fix it */
+   if (fix_one(fp, fpIn, &info, max_IDAT, strip))
+      return 1;
+
+   /* oldBits may be invalid, imageBits is always OK, newBits always records the
+    * actual window bits of the temporary file (fp).
+    */
+   bestBits = imageBits = image_windowBits(&info);
+   newBits = oldBits = 8+(info.header[0] >> 4);
+   ok_read = 0; /* records a successful read */
+
+   /* Find the optimal (lowest) newBits */
+   if (optimize)
+      for (lowBits=8; lowBits < bestBits;)
+   {
+      /* This will always set 'newBits' to a value lower than 'bestBits' because
+       * 'lowBits' is less than 'bestBits':
+       */
+      newBits = (bestBits + lowBits) >> 1;
+
+      set_bits(file, fp, &info, newBits);
+
+      rewind(fp);
+      idat_error = 0;
+
+      if (!read_png(fp))
+      {
+         /* If idat_error is *not* set this is some other problem */
+         if (!idat_error)
+            return 1;
+
+         /* This is the hypothetical case where the IDAT has too much data *and*
+          * the window size is wrong.  In fact this should never happen because
+          * of the way libpng handles a deflate stream that produces extra data.
+          */
+         if (newBits >= imageBits)
+         {
+            fprintf(stderr, "%s: imageBits(%d) too low (%d)\n", file, imageBits,
+               newBits);
+            return 1;
+         }
+
+         if (lowBits <= newBits)
+            lowBits = newBits+1;
+      }
+
+      else
+      {
+         bestBits = newBits;
+         ok_read = 1;
+      }
+   }
+
+   else if (bestBits > oldBits)
+   {
+      /* See if the original value is ok */
+      rewind(fp);
+      idat_error = 0;
+
+      if (read_png(fp))
+      {
+         ok_read = 1;
+         bestBits = oldBits;
+      }
+
+      else if (!idat_error)
+         return 1;
+
+      /* Otherwise there is an IDAT error and no optimization is being done, so
+       * just use imageBits (which is already set in bestBits).
+       */
+   }
+
+   if (newBits != bestBits)
+   {
+      /* Update the header to the required value */
+      newBits = bestBits;
+
+      set_bits(file, fp, &info, newBits);
+   }
+
+   if (!ok_read)
+   {
+      /* bestBits has not been checked */
+      idat_error = 0;
+      rewind(fp);
+      ok_read = read_png(fp);
+
+      if (idat_error)
+      {
+         /* This should never happen */
+         fprintf(stderr, "%s: imageBits(%d) too low [%d]\n", file, imageBits,
+            newBits);
+         return 1;
+      }
+
+      /* This means that the PNG has some other error */
+      if (!ok_read)
+         return 1;
+   }
+
+   /* Have a valid newBits */
+   if (optimize)
+      printf("%2d %2d %2d %s %s %d %s\n", newBits, oldBits, imageBits,
+         newBits < imageBits ? "<" : "=",
+         newBits < oldBits ? "reduce  " :
+            (newBits > oldBits ? "INCREASE" : "ok      "),
+         newBits - oldBits, name);
+
+#  ifdef PNG_MAXIMUM_INFLATE_WINDOW
+      /* Because setting libpng to use the maximum window bits breaks the
+       * read_png test above.
+       */
+      if (set_option)
+         return 0;
+#  endif
+
+   if (output != NULL || (inplace && (bestBits != oldBits || strip)))
+   {
+      FILE *fpOut;
+      
+      if (output != NULL)
+         fpOut = fopen(output, "wb");
+
+      else
+      {
+         fpOut = freopen(file, "wb", fpIn);
+         fpIn = NULL;
+      }
+      
+      if (fpOut == NULL)
+      {
+         perror(output);
+         fprintf(stderr, "%s: %s: open failed\n", file, output);
+         exit(3);
+      }
+
+      rewind(fp);
+      copy(fpOut, fp, info.file_size);
+
+      if (fflush(fpOut) || ferror(fpOut) || fclose(fpOut))
+      {
+         perror(output != NULL ? output : file);
+         fprintf(stderr, "%s: %s: close failed\n", file, output);
+         if (output != NULL)
+            remove(output);
+         exit(3);
+      }
+   }
+
+   return 0;
+}
+
+static void
+usage(const char *prog, int rc)
+{
+   /* ANSI C-90 limits strings to 509 characters, so use a string array: */
+   size_t i;
+   static const char *usage_string[] = {
+"  Tests, optimizes and optionally fixes the zlib header in PNG files.\n",
+"  Optionally, when fixing, strips ancilliary chunks from the file.\n",
+"\n",
+"OPTIONS\n",
+"  OPERATION\n",
+"      By default files are just checked for readability.\n",
+"    --optimize (-o):\n",
+"      Find the smallest deflate window size for the file, also outputs\n",
+"      a summary of the result for each file.\n",
+"    --strip (-s):\n",
+"      Remove chunks except for IHDR, PLTE, IEND, tRNS, gAMA, sRGB.  If\n",
+"      given twice remove gAMA and sRGB as well.\n",
+"    --max=<number>:\n",
+"      Use IDAT chunks sized <number>.  If not given the the IDAT\n",
+"      chunks will be the maximum size permitted; 2^31-1 bytes.\n",
+"  MESSAGES\n",
+"      By default the program is silent.\n",
+"    --errors (-e):\n",
+"      Output errors from libpng (except too-far-back).\n",
+"    --warnings (-w):\n",
+"      Output warnings from libpng.\n",
+"    --verbose (-v):\n",
+"      Describe program progress (refer to the source).\n",
+"  OUTPUT\n",
+"      By default nothing is written.\n",
+"    --out=<file>:\n",
+"      Write the optimized/corrected version of the next PNG to\n",
+"      <file>.  This overrides the following two options\n",
+"    --suffix=<suffix>:\n",
+"      Set --out=<name><suffix> for all following files, unless\n",
+"      overridden on a per-file basis by explicit --out.  If no\n",
+"      --suffix= value is given behaves as --inplace.\n",
+"    --inplace (-i):\n",
+"      Modify the file in place.  THIS IS DANGEROUS - please keep a\n",
+"      backup of the file because a program interrupt or bug will\n",
+"      result in a corrupted file.\n",
+#ifdef PNG_MAXIMUM_INFLATE_WINDOW
+"  INTERNAL OPTIONS\n",
+"    --test:\n",
+"      Test the PNG_MAXIMUM_INFLATE_WINDOW option.  Setting this\n",
+"      disables output as this would produce a broken file.\n",
+#endif
+"\n",
+"EXIT CODES\n",
+"  0: Success, all files pass the test, any output written ok.\n",
+"  1: At least one file had a read error, all files checked.\n",
+"  2: A file had an unrecoverable error (integer overflow, bad format),\n",
+"     the program exited immediately, without processing further files.\n",
+"  3: An IO or out of memory error, or a file could not be opened.h\n",
+"\n",
+"DESCRIPTION\n",
+"  " PROGRAM_NAME " checks each PNG file on the command line\n",
+"  for errors.  By default it is silent and just returns an exit code\n",
+"  (as above).  Options allow the zlib error:\n",
+"\n",
+"        \"invalid distance too far back\"\n",
+"\n",
+"  to be fixed during the read and therefore test the file for other\n",
+"  errors that may prevent reading.\n",
+"\n",
+"  Setting one of the \"OUTPUT\" options causes the possibly modified\n",
+"  file to be written to a new file or, with --inplace, to the existing\n",
+"  file.\n",
+"\n",
+"  IMPORTANT: --inplace will overwrite the original file, if you use it\n",
+"  be sure to keep a backup of the original file, this program can fail\n",
+"  during the write and has been known to have serious bugs!  A failure\n",
+"  during write will certainly damage the original file.\n",
+"\n",
+"  Notice that some PNG files with the zlib header problem can still be\n",
+"  read by libpng under some circumstances.  This program will still\n",
+"  detect and, if requested, correct the error.\n",
+"\n",
+"  The output produced with --optimize is as follows:\n",
+"\n",
+"     opt-bits curr-bits image-bits opt-flag opt-type change file\n",
+"\n",
+"   opt-bits:   The minimum window bits (8-15) that works, if the file\n",
+"               is written this is the value that will be stored.\n",
+"   curr-bits:  The value currently stored in the file.\n",
+"   image-bits: The window bits value corresponding to the size of the\n",
+"               uncompressed PNG image data.  When --optimize is not\n",
+"               given but --strip is, this value will be used if lower\n",
+"               than the current value.\n",
+"   opt-flag: < if the optimized bit value is less than that implied by\n",
+"               the PNG image size (opt-bits < image-bits)\n",
+"             = if optimization is not possible (opt-bits = image-bits)\n",
+"   opt-type: reduce   if opts-bits < curr-bits\n",
+"             ok       if opt-bits = curr-bits (no change required)\n",
+"             INCREASE if opt-bits > curr-bits (the file has the bug)\n",
+"   change:     opt-bits - curr-bits, so negative if optimization is\n",
+"               possible, 0 if no change is required, positive if the\n",
+"               bug is present.\n",
+"   file:       The file name.\n",
+};
+
+   fprintf(stderr, "Usage: %s {[options] png-file}\n", prog);
+
+   for (i=0; i < (sizeof usage_string)/(sizeof usage_string[0]); ++i)
+      fputs(usage_string[i], stderr);
+
+   exit(rc);
+}
+
+int
+main(int argc, const char **argv)
+{
+   int err, strip = 0, optimize = 0, inplace = 0, done = 0;
+   png_uint_32 max_IDAT = 0x7fffffff;
+   FILE *fp;
+   const char *outfile = NULL;
+   const char *suffix = NULL;
+   const char *prog = *argv;
+   static const png_byte idat_bytes[4] = { 73,  68,  65,  84 };
+   static const png_byte iend_bytes[4] = { 73,  69,  78,  68 };
+
+   /* Initialize this first, could be stored as a constant: */
+   crc_IEND = crc_IDAT_head = crc32(0L, Z_NULL, 0);
+   crc_IDAT_head = crc32(crc_IDAT_head, idat_bytes, 4);
+   crc_IEND = crc32(crc_IEND, iend_bytes, 4);
+
+   z_idat.next_in = Z_NULL;
+   z_idat.avail_in = 0;
+   z_idat.zalloc = Z_NULL;
+   z_idat.zfree = Z_NULL;
+   z_idat.opaque = Z_NULL;
+
+   err = inflateInit(&z_idat);
+   if (err != Z_OK)
+   {
+      fprintf(stderr, "inflateInit failed %d \"%s\"\n", err, z_idat.msg);
+      inflateEnd(&z_idat);
+      return 3;
+   }
+
+   fp = tmpfile();
+   if (fp == NULL)
+   {
+      perror("tmpfile");
+      fprintf(stderr, "could not open a temporary file\n");
+      return 3;
+   }
+
+   err = 0;
+   while (--argc > 0)
+   {
+      ++argv;
+
+      if (strcmp(*argv, "--inplace") == 0 || strcmp(*argv, "-i") == 0)
+         ++inplace;
+
+      else if (strncmp(*argv, "--max=", 6) == 0)
+         max_IDAT = (png_uint_32)atol(6+*argv);
+
+      else if (strcmp(*argv, "--optimize") == 0 || strcmp(*argv, "-o") == 0)
+         ++optimize;
+
+      else if (strncmp(*argv, "--out=", 6) == 0)
+         outfile = 6+*argv;
+
+      else if (strncmp(*argv, "--suffix=", 9) == 0)
+         suffix = 9+*argv;
+
+      else if (strcmp(*argv, "--strip") == 0 || strcmp(*argv, "-s") == 0)
+         ++strip;
+
+      else if (strcmp(*argv, "--errors") == 0 || strcmp(*argv, "-e") == 0)
+         ++errors;
+
+      else if (strcmp(*argv, "--warnings") == 0 || strcmp(*argv, "-w") == 0)
+         ++warnings;
+
+      else if (strcmp(*argv, "--verbose") == 0 || strcmp(*argv, "-v") == 0)
+         ++verbose;
+
+#     ifdef PNG_MAXIMUM_INFLATE_WINDOW
+         else if (strcmp(*argv, "--test") == 0)
+            ++set_option;
+#     endif
+
+      else if ((*argv)[0] == '-')
+         usage(prog, 3);
+
+      else
+      {
+         int ret, overwrite;
+
+         if (outfile != NULL)
+            overwrite = 0;
+
+         else if (suffix != NULL)
+         {
+            if (*suffix == 0)
+               overwrite = 1;
+
+            else
+            {
+               static char temp_name[FILENAME_MAX];
+               size_t filelen = strlen(*argv);
+               size_t suffixlen = strlen(suffix);
+
+               if (filelen + suffixlen >= FILENAME_MAX)
+               {
+                  fprintf(stderr, "%s: output file name too long: %s%s\n", prog,
+                     *argv, suffix);
+                  exit(3);
+               }
+
+               memcpy(temp_name, *argv, filelen);
+               memcpy(temp_name+filelen, suffix, suffixlen);
+               temp_name[filelen+suffixlen] = 0;
+
+               outfile = temp_name;
+               overwrite = 0;
+             }
+         }
+
+         else
+            overwrite = inplace;
+
+         err +=
+            fix_file(fp, *argv, max_IDAT, overwrite, strip, optimize, outfile);
+
+         if (fpIn != NULL)
+         {
+            fclose(fpIn);
+            fpIn = NULL;
+         }
+
+         z_idat.next_in = z_idat.next_out = Z_NULL;
+         z_idat.avail_in = z_idat.avail_out = 0;
+         ret = inflateReset(&z_idat);
+         if (ret != Z_OK)
+         {
+            fprintf(stderr, "inflateReset failed %d \"%s\"\n", ret, z_idat.msg);
+            inflateEnd(&z_idat);
+            return 3;
+         }
+
+         rewind(fp);
+         outfile = NULL;
+         ++done;
+      }
+   }
+
+   inflateEnd(&z_idat);
+
+   if (!done)
+      usage(prog, 0);
+
+   return err != 0;
+}
+
+#else /* PNG_ZLIB_VERNUM < 0x1240 */
+int
+main(void)
+{
+   fprintf(stderr,
+      "png-fix-too-far-back needs libpng with a zlib >=1.2.4 (not 0x%x)\n",
+      PNG_ZLIB_VERNUM);
+   return 77;
+}
+#endif /* PNG_ZLIB_VERNUM */
+
+#else /* No read support */
+
+int
+main(void)
+{
+   fprintf(stderr, "png-fix-too-far-back does not work without read support\n");
+   return 77;
+}
+#endif /* PNG_READ_SUPPORTED */
diff --git a/libpng-manual.txt b/libpng-manual.txt
index e289432..611f0b5 100644
--- a/libpng-manual.txt
+++ b/libpng-manual.txt
@@ -1,6 +1,6 @@
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.7.0beta13 - April 30, 2013
+ libpng version 1.7.0beta13 - May 10, 2013
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2013 Glenn Randers-Pehrson
@@ -11,7 +11,7 @@
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013
+ libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2013 Glenn Randers-Pehrson
 
@@ -5021,6 +5021,21 @@
 libpng16 and later of the GIT repository.  They continue to be included
 in the tarball releases, however.
 
+Libpng-1.6.0 and later use the CMF bytes at the beginning of the IDAT stream
+to set the size of the sliding window for reading instead of using the default
+32-kbyte sliding window size.  It was discovered that there are hundreds of PNG
+files in the wild that have incorrect CMF bytes that cause libpng to now issue
+a "too far back" error and reject the file.  Libpng-1.6.3 provides a way to
+revert to the libpng-1.5.x behavior (ignoring the CMF bytes and using a
+32-kbyte sliding window), and provides a tool
+(contrib/tools/png-fix-too-far-back) for optimizing the CMF bytes
+correctly.
+
+Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong
+length, which resulted in PNG files that cannot be read beyond the bad iTXt
+chunk.  This error was fixed in libpng-1.6.3, and a tool (called
+contrib/tools/png-fix-itxt) has been added to the libpng distribution.
+
 XIII.  Changes to Libpng from version 1.6.x to 1.7.x
 
 Some functions that were deprecated in libpng-1.6.0 were removed:
@@ -5215,7 +5230,7 @@
 
 XVII. Y2K Compliance in libpng
 
-April 30, 2013
+May 10, 2013
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
diff --git a/libpng.3 b/libpng.3
index 5a73d0c..b710075 100644
--- a/libpng.3
+++ b/libpng.3
@@ -1,4 +1,4 @@
-.TH LIBPNG 3 "April 30, 2013"
+.TH LIBPNG 3 "May 10, 2013"
 .SH NAME
 libpng \- Portable Network Graphics (PNG) Reference Library 1.7.0beta13
 .SH SYNOPSIS
@@ -494,7 +494,7 @@
 .SH LIBPNG.TXT
 libpng-manual.txt - A description on how to use and modify libpng
 
- libpng version 1.7.0beta13 - April 30, 2013
+ libpng version 1.7.0beta13 - May 10, 2013
  Updated and distributed by Glenn Randers-Pehrson
  <glennrp at users.sourceforge.net>
  Copyright (c) 1998-2013 Glenn Randers-Pehrson
@@ -505,7 +505,7 @@
 
  Based on:
 
- libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013
+ libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013
  Updated and distributed by Glenn Randers-Pehrson
  Copyright (c) 1998-2013 Glenn Randers-Pehrson
 
@@ -5516,6 +5516,21 @@
 libpng16 and later of the GIT repository.  They continue to be included
 in the tarball releases, however.
 
+Libpng-1.6.0 and later use the CMF bytes at the beginning of the IDAT stream
+to set the size of the sliding window for reading instead of using the default
+32-kbyte sliding window size.  It was discovered that there are hundreds of PNG
+files in the wild that have incorrect CMF bytes that cause libpng to now issue
+a "too far back" error and reject the file.  Libpng-1.6.3 provides a way to
+revert to the libpng-1.5.x behavior (ignoring the CMF bytes and using a
+32-kbyte sliding window), and provides a tool
+(contrib/tools/png-fix-too-far-back) for optimizing the CMF bytes
+correctly.
+
+Libpng-1.6.0 and libpng-1.6.1 wrote uncompressed iTXt chunks with the wrong
+length, which resulted in PNG files that cannot be read beyond the bad iTXt
+chunk.  This error was fixed in libpng-1.6.3, and a tool (called
+contrib/tools/png-fix-itxt) has been added to the libpng distribution.
+
 .SH XIII.  Changes to Libpng from version 1.6.x to 1.7.x
 
 Some functions that were deprecated in libpng-1.6.0 were removed:
@@ -5710,7 +5725,7 @@
 
 .SH XVII. Y2K Compliance in libpng
 
-April 30, 2013
+May 10, 2013
 
 Since the PNG Development group is an ad-hoc body, we can't make
 an official declaration.
@@ -5980,7 +5995,7 @@
 
 Thanks to Frank J. T. Wojcik for helping with the documentation.
 
-Libpng version 1.7.0beta13 - April 30, 2013:
+Libpng version 1.7.0beta13 - May 10, 2013:
 Initially created in 1995 by Guy Eric Schalnat, then of Group 42, Inc.
 Currently maintained by Glenn Randers-Pehrson (glennrp at users.sourceforge.net).
 
@@ -6003,7 +6018,7 @@
 
 This code is released under the libpng license.
 
-libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are
+libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are
 Copyright (c) 2004,2006-2007 Glenn Randers-Pehrson, and are
 distributed according to the same disclaimer and license as libpng-1.2.5
 with the following individual added to the list of Contributing Authors
@@ -6102,7 +6117,7 @@
 
 Glenn Randers-Pehrson
 glennrp at users.sourceforge.net
-April 30, 2013
+May 10, 2013
 
 .\" end of man page
 
diff --git a/libpngpf.3 b/libpngpf.3
index d385221..ff565ed 100644
--- a/libpngpf.3
+++ b/libpngpf.3
@@ -1,4 +1,4 @@
-.TH LIBPNGPF 3 "April 30, 2013"
+.TH LIBPNGPF 3 "May 10, 2013"
 .SH NAME
 libpng \- Portable Network Graphics (PNG) Reference Library 1.7.0beta13
 (private functions)
diff --git a/png.5 b/png.5
index 6b466fb..dea1235 100644
--- a/png.5
+++ b/png.5
@@ -1,4 +1,4 @@
-.TH PNG 5 "April 30, 2013"
+.TH PNG 5 "May 10, 2013"
 .SH NAME
 png \- Portable Network Graphics (PNG) format
 .SH DESCRIPTION
diff --git a/png.c b/png.c
index 39ae975..8eb6c2b 100644
--- a/png.c
+++ b/png.c
@@ -691,13 +691,13 @@
 #else
 #  ifdef __STDC__
    return PNG_STRING_NEWLINE \
-     "libpng version 1.7.0beta13 - April 30, 2013" PNG_STRING_NEWLINE \
+     "libpng version 1.7.0beta13 - May 10, 2013" PNG_STRING_NEWLINE \
      "Copyright (c) 1998-2013 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.7.0beta13 - April 30, 2013\
+      return "libpng version 1.7.0beta13 - May 10, 2013\
       Copyright (c) 1998-2013 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
diff --git a/png.h b/png.h
index 35e7fe5..63f8dec 100644
--- a/png.h
+++ b/png.h
@@ -1,7 +1,7 @@
 
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.7.0beta13 - April 30, 2013
+ * libpng version 1.7.0beta13 - May 10, 2013
  * Copyright (c) 1998-2013 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
@@ -11,7 +11,7 @@
  * Authors and maintainers:
  *   libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *   libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- *   libpng versions 0.97, January 1998, through 1.7.0beta13 - April 30, 2013: Glenn
+ *   libpng versions 0.97, January 1998, through 1.7.0beta13 - May 10, 2013: Glenn
  *   See also "Contributing Authors", below.
  *
  * Note about libpng version numbers:
@@ -200,7 +200,7 @@
  *
  * This code is released under the libpng license.
  *
- * libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, April 30, 2013, are
+ * libpng versions 1.2.6, August 15, 2004, through 1.7.0beta13, May 10, 2013, are
  * Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are
  * distributed according to the same disclaimer and license as libpng-1.2.5
  * with the following individual added to the list of Contributing Authors:
@@ -312,7 +312,7 @@
  * Y2K compliance in libpng:
  * =========================
  *
- *    April 30, 2013
+ *    May 10, 2013
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
@@ -380,7 +380,7 @@
 /* Version information for png.h - this should match the version in png.c */
 #define PNG_LIBPNG_VER_STRING "1.7.0beta13"
 #define PNG_HEADER_VERSION_STRING \
-     " libpng version 1.7.0beta13 - April 30, 2013\n"
+     " libpng version 1.7.0beta13 - May 10, 2013\n"
 
 #define PNG_LIBPNG_VER_SONUM   17
 #define PNG_LIBPNG_VER_DLLNUM  17
@@ -2916,7 +2916,8 @@
 #ifdef PNG_ARM_NEON_API_SUPPORTED
 #  define PNG_ARM_NEON   0 /* HARDWARE: ARM Neon SIMD instructions supported */
 #endif
-#define PNG_OPTION_NEXT  2 /* Next option - numbers must be even */
+#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
+#define PNG_OPTION_NEXT  4 /* Next option - numbers must be even */
 
 /* Return values: NOTE: there are four values and 'off' is *not* zero */
 #define PNG_OPTION_UNSET   0 /* Unset - defaults to off */
diff --git a/pngconf.h b/pngconf.h
index a75e0d5..a0164b7 100644
--- a/pngconf.h
+++ b/pngconf.h
@@ -1,7 +1,7 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.7.0beta13 - April 30, 2013
+ * libpng version 1.7.0beta13 - May 10, 2013
  *
  * Copyright (c) 1998-2013 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
diff --git a/pngpriv.h b/pngpriv.h
index 3e137b5..b6725d2 100644
--- a/pngpriv.h
+++ b/pngpriv.h
@@ -629,6 +629,24 @@
 #include "pngstruct.h"
 #include "pnginfo.h"
 
+/* Validate the include paths - the include path used to generate pnglibconf.h
+ * must match that used in the build, or we must be using pnglibconf.h.prebuilt:
+ */
+#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM
+#  error ZLIB_VERNUM != PNG_ZLIB_VERNUM \
+      "-I (include path) error: see the notes in pngpriv.h"
+   /* This means that when pnglibconf.h was built the copy of zlib.h that it
+    * used is not the same as the one being used here.  Because the build of
+    * libpng makes decisions to use inflateInit2 and inflateReset2 based on the
+    * zlib version number and because this affects handling of certain broken
+    * PNG files the -I directives must match.
+    *
+    * The most likely explanation is that you passed a -I in CFLAGS, this will
+    * not work; all the preprocessor directories and in particular all the -I
+    * directives must be in CPPFLAGS.
+    */
+#endif
+
 /* This is used for 16 bit gamma tables -- only the top level pointers are
  * const; this could be changed:
  */
diff --git a/pngrutil.c b/pngrutil.c
index b82b4ea..29154e1 100644
--- a/pngrutil.c
+++ b/pngrutil.c
@@ -311,7 +311,7 @@
  * chunk apparently owns the stream.  Prior to release it does a png_error.
  */
 static int
-png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits)
+png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
 {
    if (png_ptr->zowner != 0)
    {
@@ -346,6 +346,22 @@
     */
    {
       int ret; /* zlib return code */
+#     if PNG_ZLIB_VERNUM >= 0x1240
+
+#        if defined(PNG_SET_OPTION_SUPPORTED) && \
+            defined(PNG_MAXIMUM_INFLATE_WINDOW)
+            int window_bits;
+
+            if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) ==
+               PNG_OPTION_ON)
+               window_bits = 15;
+
+            else
+               window_bits = 0;
+#        else
+#           define window_bits 0
+#        endif
+#     endif
 
       /* Set this for safety, just in case the previous owner left pointers to
        * memory allocations.
@@ -357,8 +373,7 @@
 
       if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED)
       {
-#        if ZLIB_VERNUM < 0x1240
-            PNG_UNUSED(window_bits)
+#        if PNG_ZLIB_VERNUM < 0x1240
             ret = inflateReset(&png_ptr->zstream);
 #        else
             ret = inflateReset2(&png_ptr->zstream, window_bits);
@@ -367,7 +382,7 @@
 
       else
       {
-#        if ZLIB_VERNUM < 0x1240
+#        if PNG_ZLIB_VERNUM < 0x1240
             ret = inflateInit(&png_ptr->zstream);
 #        else
             ret = inflateInit2(&png_ptr->zstream, window_bits);
@@ -385,6 +400,10 @@
 
       return ret;
    }
+
+#  ifdef window_bits
+#     undef window_bits
+#  endif
 }
 
 #ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
@@ -557,14 +576,8 @@
       if (limit < *newlength)
          *newlength = limit;
 
-      /* Now try to claim the stream; the 'warn' setting causes zlib to be told
-       * to use the maximum window size during inflate; this hides errors in the
-       * deflate header window bits value which is used if '0' is passed.  In
-       * fact this only has an effect with zlib versions 1.2.4 and later - see
-       * the comments in png_inflate_claim above.
-       */
-      ret = png_inflate_claim(png_ptr, png_ptr->chunk_name,
-         png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0);
+      /* Now try to claim the stream. */
+      ret = png_inflate_claim(png_ptr, png_ptr->chunk_name);
 
       if (ret == Z_OK)
       {
@@ -1334,8 +1347,7 @@
          {
             read_length -= keyword_length+2;
 
-            if (png_inflate_claim(png_ptr, png_iCCP,
-               png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK)
+            if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK)
             {
                Byte profile_header[132];
                Byte local_buffer[PNG_INFLATE_BUF_SIZE];
@@ -4412,7 +4424,7 @@
     * IDAT stream has a bogus deflate header window_bits value, but this should
     * not be happening any longer!)
     */
-   if (png_inflate_claim(png_ptr, png_IDAT, 0) != Z_OK)
+   if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK)
       png_error(png_ptr, png_ptr->zstream.msg);
 
    png_ptr->flags |= PNG_FLAG_ROW_INIT;
diff --git a/projects/vstudio/readme.txt b/projects/vstudio/readme.txt
index 2cab710..28050f3 100644
--- a/projects/vstudio/readme.txt
+++ b/projects/vstudio/readme.txt
@@ -1,7 +1,7 @@
 
 VisualStudio instructions
 
-libpng version 1.7.0beta13 - April 30, 2013
+libpng version 1.7.0beta13 - May 10, 2013
 
 Copyright (c) 1998-2010 Glenn Randers-Pehrson
 
diff --git a/projects/vstudio/zlib.props b/projects/vstudio/zlib.props
index 27d0082..c26c20c 100644
--- a/projects/vstudio/zlib.props
+++ b/projects/vstudio/zlib.props
@@ -2,7 +2,7 @@
 <!--
  * zlib.props - location of zlib source
  *
- * libpng version 1.7.0beta13 - April 30, 2013
+ * libpng version 1.7.0beta13 - May 10, 2013
  *
  * Copyright (c) 1998-2011 Glenn Randers-Pehrson
  *
diff --git a/scripts/README.txt b/scripts/README.txt
index d0e359a..3701ead 100644
--- a/scripts/README.txt
+++ b/scripts/README.txt
@@ -1,5 +1,5 @@
 
-Makefiles for  libpng version 1.7.0beta13 - April 30, 2013
+Makefiles for  libpng version 1.7.0beta13 - May 10, 2013
 
 pnglibconf.h.prebuilt       =>  Stores configuration settings
  makefile.linux    =>  Linux/ELF makefile
diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa
index cd3b3c6..77cc7ab 100644
--- a/scripts/pnglibconf.dfa
+++ b/scripts/pnglibconf.dfa
@@ -238,6 +238,7 @@
 # ARM_NEON: the optimization itself
 # ARM_NEON_API: allow the optimization to be switched on with png_set_hardware
 # ARM_NEON_CHECK: compile a run-time check to see if Neon extensions are
+setting ZLIB_VERNUM default @ZLIB_VERNUM
 #                 supported, this is poorly supported and deprectated - use the
 #                 png_set_hardware API.
 option ARM_NEON disabled,
@@ -425,7 +426,7 @@
 # to libpng 1.6; the new interfaces in 1.6 will take several years to become
 # popular.
 
-option READ enables READ_INTERLACING
+option READ enables READ_INTERLACING SET_OPTION
 
 # Disabling READ_16BIT does not disable reading 16-bit PNG files, but it
 # forces them to be chopped down to 8-bit, and disables any 16-bit
diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt
index 88865d3..7c39e3c 100644
--- a/scripts/pnglibconf.h.prebuilt
+++ b/scripts/pnglibconf.h.prebuilt
@@ -2,7 +2,7 @@
 
 /* pnglibconf.h - library build configuration */
 
-/* Libpng version 1.7.0beta13 - April 30, 2013 */
+/* Libpng version 1.7.0beta13 - May 10, 2013 */
 
 /* Copyright (c) 1998-2013 Glenn Randers-Pehrson */
 
@@ -103,7 +103,7 @@
 #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
 #define PNG_SEQUENTIAL_READ_SUPPORTED
 #define PNG_SETJMP_SUPPORTED
-/*#undef PNG_SET_OPTION_SUPPORTED*/
+#define PNG_SET_OPTION_SUPPORTED
 #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
 #define PNG_SET_USER_LIMITS_SUPPORTED
 #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
@@ -200,6 +200,7 @@
 #define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
 #define PNG_TEXT_Z_DEFAULT_STRATEGY 0
 #define PNG_WEIGHT_SHIFT 8
+#define PNG_ZLIB_VERNUM 0 /* unknown */
 #define PNG_ZBUF_SIZE 8192
 #define PNG_ZLIB_HEADER <zlib.h>
 #define PNG_Z_DEFAULT_COMPRESSION (-1)