[DINPUT]
[reactos.git] / reactos / dll / 3rdparty / libpng / pngrutil.c
index d476431..5ee452d 100644 (file)
@@ -1,8 +1,8 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.5.2 [March 31, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.14 [January 24, 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.)
  *
@@ -87,10 +87,10 @@ png_int_32 (PNGAPI
 png_get_int_32)(png_const_bytep buf)
 {
    png_uint_32 uval = png_get_uint_32(buf);
-   if ((uval & 0x80000000L) == 0) /* non-negative */
+   if ((uval & 0x80000000) == 0) /* non-negative */
       return uval;
 
-   uval = (uval ^ 0xffffffffL) + 1;  /* 2's complement: -x = ~x+1 */
+   uval = (uval ^ 0xffffffff) + 1;  /* 2's complement: -x = ~x+1 */
    return -(png_int_32)uval;
 }
 
@@ -165,14 +165,14 @@ png_read_chunk_header(png_structp png_ptr)
    length = png_get_uint_31(png_ptr, buf);
 
    /* Put the chunk name into png_ptr->chunk_name. */
-   png_memcpy(png_ptr->chunk_name, buf + 4, 4);
+   png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
 
-   png_debug2(0, "Reading %s chunk, length = %u",
-       png_ptr->chunk_name, length);
+   png_debug2(0, "Reading %lx chunk, length = %lu",
+       (unsigned long)png_ptr->chunk_name, (unsigned long)length);
 
    /* Reset the crc and run it over the chunk name. */
    png_reset_crc(png_ptr);
-   png_calculate_crc(png_ptr, png_ptr->chunk_name, 4);
+   png_calculate_crc(png_ptr, buf + 4, 4);
 
    /* Check to see if chunk name is valid. */
    png_check_chunk_name(png_ptr, png_ptr->chunk_name);
@@ -218,10 +218,9 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip)
 
    if (png_crc_error(png_ptr))
    {
-      if (((png_ptr->chunk_name[0] & 0x20) &&                /* Ancillary */
-          !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
-          (!(png_ptr->chunk_name[0] & 0x20) &&             /* Critical  */
-          (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
+      if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name) ?
+          !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) :
+          (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))
       {
          png_chunk_warning(png_ptr, "CRC error");
       }
@@ -248,14 +247,14 @@ png_crc_error(png_structp png_ptr)
    png_uint_32 crc;
    int need_crc = 1;
 
-   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   if (PNG_CHUNK_ANCILLIARY(png_ptr->chunk_name))
    {
       if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
           (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
          need_crc = 0;
    }
 
-   else                                                    /* critical */
+   else /* critical */
    {
       if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
          need_crc = 0;
@@ -278,8 +277,7 @@ png_crc_error(png_structp png_ptr)
       return (0);
 }
 
-#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
-    defined(PNG_READ_iCCP_SUPPORTED)
+#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED
 static png_size_t
 png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
     png_bytep output, png_size_t output_size)
@@ -303,7 +301,7 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
    {
       int ret, avail;
 
-      /* The setting of 'avail_in' used to be outside the loop, by setting it
+      /* The setting of 'avail_in' used to be outside the loop; by setting it
        * inside it is possible to chunk the input to zlib and simply rely on
        * zlib to advance the 'next_in' pointer.  This allows arbitrary amounts o
        * data to be passed through zlib at the unavoidable cost of requiring a
@@ -370,41 +368,31 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
        * and the error message is dumped into the uncompressed
        * buffer if available.
        */
+#     ifdef PNG_WARNINGS_SUPPORTED
       {
-         PNG_CONST char *msg;
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         char umsg[52];
-#endif
+         png_const_charp msg;
+
          if (png_ptr->zstream.msg != 0)
             msg = png_ptr->zstream.msg;
 
-         else
+         else switch (ret)
          {
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-            switch (ret)
-            {
-               case Z_BUF_ERROR:
-                  msg = "Buffer error in compressed datastream in %s chunk";
-                  break;
-
-               case Z_DATA_ERROR:
-                  msg = "Data error in compressed datastream in %s chunk";
-                  break;
+            case Z_BUF_ERROR:
+               msg = "Buffer error in compressed datastream";
+               break;
 
-               default:
-                  msg = "Incomplete compressed datastream in %s chunk";
-                  break;
-            }
+            case Z_DATA_ERROR:
+               msg = "Data error in compressed datastream";
+               break;
 
-            png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name);
-            msg = umsg;
-#else
-            msg = "Damaged compressed datastream in chunk other than IDAT";
-#endif
+            default:
+               msg = "Incomplete compressed datastream";
+               break;
          }
 
-         png_warning(png_ptr, msg);
+         png_chunk_warning(png_ptr, msg);
       }
+#     endif
 
       /* 0 means an error - notice that this code simply ignores
        * zero length compressed chunks as a result.
@@ -438,21 +426,22 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
       png_size_t expanded_size = png_inflate(png_ptr,
           (png_bytep)(png_ptr->chunkdata + prefix_size),
           chunklength - prefix_size,
-          0,            /*output*/
-          0);           /*output size*/
+          0,            /* output */
+          0);           /* output size */
 
       /* Now check the limits on this chunk - if the limit fails the
        * compressed data will be removed, the prefix will remain.
        */
-#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
-      if (png_ptr->user_chunk_malloc_max &&
+      if (prefix_size >= (~(png_size_t)0) - 1 ||
+         expanded_size >= (~(png_size_t)0) - 1 - prefix_size
+#ifdef PNG_USER_LIMITS_SUPPORTED
+         || (png_ptr->user_chunk_malloc_max &&
           (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
 #else
-#  ifdef PNG_USER_CHUNK_MALLOC_MAX
-      if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
+         || ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
           prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
-#  endif
 #endif
+         )
          png_warning(png_ptr, "Exceeded size limit while expanding chunk");
 
       /* If the size is zero either there was an error and a message
@@ -460,16 +449,11 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
        * and we have nothing to do - the code will exit through the
        * error case below.
        */
-#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
-    defined(PNG_USER_CHUNK_MALLOC_MAX)
       else if (expanded_size > 0)
-#else
-      if (expanded_size > 0)
-#endif
       {
          /* Success (maybe) - really uncompress the chunk. */
          png_size_t new_size = 0;
-         png_charp text = png_malloc_warn(png_ptr,
+         png_charp text = (png_charp)png_malloc_warn(png_ptr,
              prefix_size + expanded_size + 1);
 
          if (text != NULL)
@@ -500,15 +484,9 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
 
    else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
    {
-#ifdef PNG_STDIO_SUPPORTED
-      char umsg[50];
-
-      png_snprintf(umsg, sizeof umsg,
-          "Unknown zTXt compression type %d", comp_type);
-      png_warning(png_ptr, umsg);
-#else
-      png_warning(png_ptr, "Unknown zTXt compression type");
-#endif
+      PNG_WARNING_PARAMETERS(p)
+      png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type);
+      png_formatted_warning(png_ptr, p, "Unknown compression type @1");
 
       /* The recovery is to simply drop the data. */
    }
@@ -518,7 +496,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
     * amount of compressed data.
     */
    {
-      png_charp text = png_malloc_warn(png_ptr, prefix_size + 1);
+      png_charp text = (png_charp)png_malloc_warn(png_ptr, prefix_size + 1);
 
       if (text != NULL)
       {
@@ -536,7 +514,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
 
    *newlength = prefix_size;
 }
-#endif
+#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */
 
 /* Read and check the IDHR chunk */
 void /* PRIVATE */
@@ -844,14 +822,12 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 #  ifdef PNG_READ_sRGB_SUPPORTED
    if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
    {
-      if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
+      if (PNG_OUT_OF_RANGE(igamma, 45500, 500))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect gAMA value when sRGB is also present");
-
-#    ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "gamma = (%d/100000)", (int)igamma);
-#    endif
+         PNG_WARNING_PARAMETERS(p)
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma);
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect gAMA value @1 when sRGB is also present");
          return;
       }
    }
@@ -961,7 +937,7 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    else if (png_ptr->mode & PNG_HAVE_PLTE)
       /* Should be an error, but we can cope with it */
-      png_warning(png_ptr, "Missing PLTE before cHRM");
+      png_warning(png_ptr, "Out of place cHRM chunk");
 
    if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
 #  ifdef PNG_READ_sRGB_SUPPORTED
@@ -1013,28 +989,112 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    {
       if (PNG_OUT_OF_RANGE(x_white, 31270,  1000) ||
           PNG_OUT_OF_RANGE(y_white, 32900,  1000) ||
-          PNG_OUT_OF_RANGE(x_red,   64000L, 1000) ||
+          PNG_OUT_OF_RANGE(x_red,   64000 1000) ||
           PNG_OUT_OF_RANGE(y_red,   33000,  1000) ||
           PNG_OUT_OF_RANGE(x_green, 30000,  1000) ||
-          PNG_OUT_OF_RANGE(y_green, 60000L, 1000) ||
+          PNG_OUT_OF_RANGE(y_green, 60000 1000) ||
           PNG_OUT_OF_RANGE(x_blue,  15000,  1000) ||
           PNG_OUT_OF_RANGE(y_blue,   6000,  1000))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect cHRM value when sRGB is also present");
-
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "wx=%d, wy=%d, rx=%d, ry=%d\n",
-             x_white, y_white, x_red, y_red);
-
-         fprintf(stderr, "gx=%d, gy=%d, bx=%d, by=%d\n",
-             x_green, y_green, x_blue, y_blue);
-#endif /* PNG_CONSOLE_IO_SUPPORTED */
+         PNG_WARNING_PARAMETERS(p)
+
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white);
+         png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white);
+         png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red);
+         png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red);
+         png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green);
+         png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green);
+         png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue);
+         png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue);
+
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) "
+             "when sRGB is also present");
       }
       return;
    }
 #endif /* PNG_READ_sRGB_SUPPORTED */
 
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+   /* Store the _white values as default coefficients for the rgb to gray
+    * operation if it is supported.  Check if the transform is already set to
+    * avoid destroying the transform values.
+    */
+   if (!png_ptr->rgb_to_gray_coefficients_set)
+   {
+      /* png_set_background has not been called and we haven't seen an sRGB
+       * chunk yet.  Find the XYZ of the three end points.
+       */
+      png_XYZ XYZ;
+      png_xy xy;
+
+      xy.redx = x_red;
+      xy.redy = y_red;
+      xy.greenx = x_green;
+      xy.greeny = y_green;
+      xy.bluex = x_blue;
+      xy.bluey = y_blue;
+      xy.whitex = x_white;
+      xy.whitey = y_white;
+
+      if (png_XYZ_from_xy_checked(png_ptr, &XYZ, xy))
+      {
+         /* The success case, because XYZ_from_xy normalises to a reference
+          * white Y of 1.0 we just need to scale the numbers.  This should
+          * always work just fine. It is an internal error if this overflows.
+          */
+         {
+            png_fixed_point r, g, b;
+            if (png_muldiv(&r, XYZ.redY, 32768, PNG_FP_1) &&
+               r >= 0 && r <= 32768 &&
+               png_muldiv(&g, XYZ.greenY, 32768, PNG_FP_1) &&
+               g >= 0 && g <= 32768 &&
+               png_muldiv(&b, XYZ.blueY, 32768, PNG_FP_1) &&
+               b >= 0 && b <= 32768 &&
+               r+g+b <= 32769)
+            {
+               /* We allow 0 coefficients here.  r+g+b may be 32769 if two or
+                * all of the coefficients were rounded up.  Handle this by
+                * reducing the *largest* coefficient by 1; this matches the
+                * approach used for the default coefficients in pngrtran.c
+                */
+               int add = 0;
+
+               if (r+g+b > 32768)
+                  add = -1;
+               else if (r+g+b < 32768)
+                  add = 1;
+
+               if (add != 0)
+               {
+                  if (g >= r && g >= b)
+                     g += add;
+                  else if (r >= g && r >= b)
+                     r += add;
+                  else
+                     b += add;
+               }
+
+               /* Check for an internal error. */
+               if (r+g+b != 32768)
+                  png_error(png_ptr,
+                     "internal error handling cHRM coefficients");
+
+               png_ptr->rgb_to_gray_red_coeff   = (png_uint_16)r;
+               png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g;
+            }
+
+            /* This is a png_error at present even though it could be ignored -
+             * it should never happen, but it is important that if it does, the
+             * bug is fixed.
+             */
+            else
+               png_error(png_ptr, "internal error handling cHRM->XYZ");
+         }
+      }
+   }
+#endif
+
    png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red,
       x_green, y_green, x_blue, y_blue);
 }
@@ -1094,13 +1154,15 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
    if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
    {
-      if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500))
+      if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500, 500))
       {
-         png_warning(png_ptr,
-             "Ignoring incorrect gAMA value when sRGB is also present");
-#ifdef PNG_CONSOLE_IO_SUPPORTED
-         fprintf(stderr, "incorrect gamma=(%d/100000)\n", info_ptr->gamma);
-#endif
+         PNG_WARNING_PARAMETERS(p)
+
+         png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed,
+            info_ptr->gamma);
+
+         png_formatted_warning(png_ptr, p,
+             "Ignoring incorrect gAMA value @1 when sRGB is also present");
       }
    }
 #endif /* PNG_READ_gAMA_SUPPORTED */
@@ -1109,10 +1171,10 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
       if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270,  1000) ||
           PNG_OUT_OF_RANGE(info_ptr->y_white, 32900,  1000) ||
-          PNG_OUT_OF_RANGE(info_ptr->x_red,   64000L, 1000) ||
+          PNG_OUT_OF_RANGE(info_ptr->x_red,   64000 1000) ||
           PNG_OUT_OF_RANGE(info_ptr->y_red,   33000,  1000) ||
           PNG_OUT_OF_RANGE(info_ptr->x_green, 30000,  1000) ||
-          PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) ||
+          PNG_OUT_OF_RANGE(info_ptr->y_green, 60000 1000) ||
           PNG_OUT_OF_RANGE(info_ptr->x_blue,  15000,  1000) ||
           PNG_OUT_OF_RANGE(info_ptr->y_blue,   6000,  1000))
       {
@@ -1121,6 +1183,47 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       }
 #endif /* PNG_READ_cHRM_SUPPORTED */
 
+   /* This is recorded for use when handling the cHRM chunk above.  An sRGB
+    * chunk unconditionally overwrites the coefficients for grayscale conversion
+    * too.
+    */
+   png_ptr->is_sRGB = 1;
+
+#  ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+      /* Don't overwrite user supplied values: */
+      if (!png_ptr->rgb_to_gray_coefficients_set)
+      {
+         /* These numbers come from the sRGB specification (or, since one has to
+          * pay much money to get a copy, the wikipedia sRGB page) the
+          * chromaticity values quoted have been inverted to get the reverse
+          * transformation from RGB to XYZ and the 'Y' coefficients scaled by
+          * 32768 (then rounded).
+          *
+          * sRGB and ITU Rec-709 both truncate the values for the D65 white
+          * point to four digits and, even though it actually stores five
+          * digits, the PNG spec gives the truncated value.
+          *
+          * This means that when the chromaticities are converted back to XYZ
+          * end points we end up with (6968,23435,2366), which, as described in
+          * pngrtran.c, would overflow.  If the five digit precision and up is
+          * used we get, instead:
+          *
+          *    6968*R + 23435*G + 2365*B
+          *
+          * (Notice that this rounds the blue coefficient down, rather than the
+          * choice used in pngrtran.c which is to round the green one down.)
+          */
+         png_ptr->rgb_to_gray_red_coeff   =  6968; /* 0.212639005871510 */
+         png_ptr->rgb_to_gray_green_coeff = 23434; /* 0.715168678767756 */
+         /* png_ptr->rgb_to_gray_blue_coeff  =  2366; 0.072192315360734        */
+
+         /* The following keeps the cHRM chunk from destroying the
+          * coefficients again in the event that it follows the sRGB chunk.
+          */
+         png_ptr->rgb_to_gray_coefficients_set = 1;
+      }
+#  endif
+
    png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
 }
 #endif /* PNG_READ_sRGB_SUPPORTED */
@@ -1154,13 +1257,16 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       /* Should be an error, but we can cope with it */
       png_warning(png_ptr, "Out of place iCCP chunk");
 
-   if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+   if ((png_ptr->mode & PNG_HAVE_iCCP) || (info_ptr != NULL &&
+      (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB))))
    {
       png_warning(png_ptr, "Duplicate iCCP chunk");
       png_crc_finish(png_ptr, length);
       return;
    }
 
+   png_ptr->mode |= PNG_HAVE_iCCP;
+
 #ifdef PNG_MAX_MALLOC_64K
    if (length > (png_uint_32)65535L)
    {
@@ -1172,7 +1278,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    png_free(png_ptr, png_ptr->chunkdata);
    png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -1240,23 +1346,15 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* And the following guarantees that profile_size == profile_length. */
    if (profile_size > profile_length)
    {
+      PNG_WARNING_PARAMETERS(p)
+
       png_free(png_ptr, png_ptr->chunkdata);
       png_ptr->chunkdata = NULL;
-#ifdef PNG_STDIO_SUPPORTED
-      {
-         char umsg[80];
-
-         png_snprintf2(umsg, 80,
-             "Ignoring iCCP chunk with declared size = %u "
-              "and actual length = %u",
-              (unsigned int) profile_size,
-              (unsigned int) profile_length);
-         png_warning(png_ptr, umsg);
-      }
-#else
-      png_warning(png_ptr,
-         "Ignoring iCCP chunk with uncompressed size mismatch");
-#endif
+
+      png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size);
+      png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length);
+      png_formatted_warning(png_ptr, p,
+         "Ignoring iCCP chunk with declared size = @1 and actual length = @2");
       return;
    }
 
@@ -1330,7 +1428,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
     * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
     * potential breakage point if the types in pngconf.h aren't exactly right.
     */
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -1565,6 +1663,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 {
    png_size_t truelen;
    png_byte buf[6];
+   png_color_16 background;
 
    png_debug(1, "in png_handle_bKGD");
 
@@ -1621,7 +1720,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
     */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
    {
-      png_ptr->background.index = buf[0];
+      background.index = buf[0];
 
       if (info_ptr && info_ptr->num_palette)
       {
@@ -1631,33 +1730,36 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
             return;
          }
 
-         png_ptr->background.red =
-             (png_uint_16)png_ptr->palette[buf[0]].red;
+         background.red = (png_uint_16)png_ptr->palette[buf[0]].red;
+         background.green = (png_uint_16)png_ptr->palette[buf[0]].green;
+         background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue;
+      }
 
-         png_ptr->background.green =
-             (png_uint_16)png_ptr->palette[buf[0]].green;
+      else
+         background.red = background.green = background.blue = 0;
 
-         png_ptr->background.blue =
-             (png_uint_16)png_ptr->palette[buf[0]].blue;
-      }
+      background.gray = 0;
    }
 
    else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
    {
-      png_ptr->background.red =
-      png_ptr->background.green =
-      png_ptr->background.blue =
-      png_ptr->background.gray = png_get_uint_16(buf);
+      background.index = 0;
+      background.red =
+      background.green =
+      background.blue =
+      background.gray = png_get_uint_16(buf);
    }
 
    else
    {
-      png_ptr->background.red = png_get_uint_16(buf);
-      png_ptr->background.green = png_get_uint_16(buf + 2);
-      png_ptr->background.blue = png_get_uint_16(buf + 4);
+      background.index = 0;
+      background.red = png_get_uint_16(buf);
+      background.green = png_get_uint_16(buf + 2);
+      background.blue = png_get_uint_16(buf + 4);
+      background.gray = 0;
    }
 
-   png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+   png_set_bKGD(png_ptr, info_ptr, &background);
 }
 #endif
 
@@ -1694,16 +1796,16 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   num = length / 2 ;
-
-   if (num != (unsigned int)png_ptr->num_palette || num >
-       (unsigned int)PNG_MAX_PALETTE_LENGTH)
+   if (length > 2*PNG_MAX_PALETTE_LENGTH ||
+       length != (unsigned int) (2*png_ptr->num_palette))
    {
       png_warning(png_ptr, "Incorrect hIST chunk length");
       png_crc_finish(png_ptr, length);
       return;
    }
 
+   num = length / 2 ;
+
    for (i = 0; i < num; i++)
    {
       png_byte buf[2];
@@ -1853,7 +1955,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -1982,6 +2084,14 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
+   /* Need unit type, width, \0, height: minimum 4 bytes */
+   else if (length < 4)
+   {
+      png_warning(png_ptr, "sCAL chunk too short");
+      png_crc_finish(png_ptr, length);
+      return;
+   }
+
    png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)",
       length + 1);
 
@@ -1994,7 +2104,7 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
    png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
 
@@ -2017,23 +2127,29 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    /* Validate the ASCII numbers, need two ASCII numbers separated by
     * a '\0' and they need to fit exactly in the chunk data.
     */
-   i = 0;
+   i = 1;
    state = 0;
 
-   if (png_ptr->chunkdata[1] == 45 /* negative width */ ||
-       !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
+   if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
        i >= slength || png_ptr->chunkdata[i++] != 0)
       png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format");
 
+   else if (!PNG_FP_IS_POSITIVE(state))
+      png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width");
+
    else
    {
       png_size_t heighti = i;
 
-      if (png_ptr->chunkdata[i] == 45 /* negative height */ ||
-          !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
+      state = 0;
+      if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) ||
           i != slength)
          png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format");
 
+      else if (!PNG_FP_IS_POSITIVE(state))
+         png_warning(png_ptr,
+            "Invalid sCAL chunk ignored: non-positive height");
+
       else
          /* This is the (only) success case. */
          png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0],
@@ -2148,7 +2264,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
      return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, skip))
@@ -2256,7 +2372,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -2336,7 +2452,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_textp text_ptr;
    png_charp key, lang, text, lang_key;
    int comp_flag;
-   int comp_type = 0;
+   int comp_type;
    int ret;
    png_size_t slength, prefix_len, data_len;
 
@@ -2387,7 +2503,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   slength = (png_size_t)length;
+   slength = length;
    png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
 
    if (png_crc_finish(png_ptr, 0))
@@ -2417,10 +2533,27 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   else
+   comp_flag = *lang++;
+   comp_type = *lang++;
+
+   /* 1.5.14: The spec says "for uncompressed text decoders shall ignore [the
+    * compression type]".  The compression flag shall be 0 (no compression) or
+    * 1 (compressed with method 0 - deflate.)
+    */
+   if (comp_flag != 0 && comp_flag != 1)
+   {
+      png_warning(png_ptr, "invalid iTXt compression flag");
+      png_free(png_ptr, png_ptr->chunkdata);
+      png_ptr->chunkdata = NULL;
+      return;
+   }
+
+   if (comp_flag/*compressed*/ && comp_type != 0)
    {
-      comp_flag = *lang++;
-      comp_type = *lang++;
+      png_warning(png_ptr, "unknown iTXt compression type");
+      png_free(png_ptr, png_ptr->chunkdata);
+      png_ptr->chunkdata = NULL;
+      return;
    }
 
    for (lang_key = lang; *lang_key; lang_key++)
@@ -2453,7 +2586,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    key=png_ptr->chunkdata;
 
-   if (comp_flag)
+   if (comp_flag/*compressed*/)
       png_decompress_chunk(png_ptr, comp_type,
           (size_t)length, prefix_len, &data_len);
 
@@ -2471,7 +2604,8 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       return;
    }
 
-   text_ptr->compression = (int)comp_flag + 1;
+   text_ptr->compression =
+      (comp_flag ? PNG_ITXT_COMPRESSION_zTXt : PNG_ITXT_COMPRESSION_NONE);
    text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
    text_ptr->lang = png_ptr->chunkdata + (lang - key);
    text_ptr->itxt_length = data_len;
@@ -2523,16 +2657,14 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
    if (png_ptr->mode & PNG_HAVE_IDAT)
    {
-      PNG_IDAT;
-
-      if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))  /* Not an IDAT */
+      if (png_ptr->chunk_name != png_IDAT)
          png_ptr->mode |= PNG_AFTER_IDAT;
    }
 
-   if (!(png_ptr->chunk_name[0] & 0x20))
+   if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
    {
 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-      if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+      if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) !=
           PNG_HANDLE_CHUNK_ALWAYS
 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
           && png_ptr->read_user_chunk_fn == NULL
@@ -2550,21 +2682,20 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
        )
    {
 #ifdef PNG_MAX_MALLOC_64K
-      if (length > (png_uint_32)65535L)
+      if (length > 65535)
       {
          png_warning(png_ptr, "unknown chunk too large to fit in memory");
-         skip = length - (png_uint_32)65535L;
-         length = (png_uint_32)65535L;
+         skip = length - 65535;
+         length = 65535;
       }
 #endif
 
-      png_memcpy((png_charp)png_ptr->unknown_chunk.name,
-          (png_charp)png_ptr->chunk_name,
-          png_sizeof(png_ptr->unknown_chunk.name));
-
-      png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1]
-          = '\0';
-
+      /* TODO: this code is very close to the unknown handling in pngpread.c,
+       * maybe it can be put into a common utility routine?
+       * png_struct::unknown_chunk is just used as a temporary variable, along
+       * with the data into which the chunk is read.  These can be eliminated.
+       */
+      PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
       png_ptr->unknown_chunk.size = (png_size_t)length;
 
       if (length == 0)
@@ -2573,7 +2704,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
       else
       {
          png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
-         png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
+         png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length);
       }
 
 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
@@ -2590,10 +2721,10 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
 
          if (ret == 0)
          {
-            if (!(png_ptr->chunk_name[0] & 0x20))
+            if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
             {
 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-               if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+               if (png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name) !=
                    PNG_HANDLE_CHUNK_ALWAYS)
 #endif
                   png_chunk_error(png_ptr, "unknown critical chunk");
@@ -2630,259 +2761,523 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
  * the chunk name itself is valid.
  */
 
-#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is:
+ *
+ * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+ */
 
 void /* PRIVATE */
-png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name)
+png_check_chunk_name(png_structp png_ptr, png_uint_32 chunk_name)
 {
+   int i;
+
    png_debug(1, "in png_check_chunk_name");
-   if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
-       isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+
+   for (i=1; i<=4; ++i)
    {
-      png_chunk_error(png_ptr, "invalid chunk type");
+      int c = chunk_name & 0xff;
+
+      if (c < 65 || c > 122 || (c > 90 && c < 97))
+         png_chunk_error(png_ptr, "invalid chunk type");
+
+      chunk_name >>= 8;
    }
 }
 
-/* Combines the row recently read in with the existing pixels in the
- * row.  This routine takes care of alpha and transparency if requested.
- * This routine also handles the two methods of progressive display
- * of interlaced images, depending on the mask value.
- * The mask value describes which pixels are to be combined with
- * the row.  The pattern always repeats every 8 pixels, so just 8
- * bits are needed.  A one indicates the pixel is to be combined,
- * a zero indicates the pixel is to be skipped.  This is in addition
- * to any alpha or transparency value associated with the pixel.  If
- * you want all pixels to be combined, pass 0xff (255) in mask.
+/* Combines the row recently read in with the existing pixels in the row.  This
+ * routine takes care of alpha and transparency if requested.  This routine also
+ * handles the two methods of progressive display of interlaced images,
+ * depending on the 'display' value; if 'display' is true then the whole row
+ * (dp) is filled from the start by replicating the available pixels.  If
+ * 'display' is false only those pixels present in the pass are filled in.
  */
-
 void /* PRIVATE */
-png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+png_combine_row(png_structp png_ptr, png_bytep dp, int display)
 {
+   unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
+   png_const_bytep sp = png_ptr->row_buf + 1;
+   png_uint_32 row_width = png_ptr->width;
+   unsigned int pass = png_ptr->pass;
+   png_bytep end_ptr = 0;
+   png_byte end_byte = 0;
+   unsigned int end_mask;
+
    png_debug(1, "in png_combine_row");
 
-   if (mask == 0xff)
+   /* Added in 1.5.6: it should not be possible to enter this routine until at
+    * least one row has been read from the PNG data and transformed.
+    */
+   if (pixel_depth == 0)
+      png_error(png_ptr, "internal row logic error");
+
+   /* Added in 1.5.4: the pixel depth should match the information returned by
+    * any call to png_read_update_info at this point.  Do not continue if we got
+    * this wrong.
+    */
+   if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes !=
+          PNG_ROWBYTES(pixel_depth, row_width))
+      png_error(png_ptr, "internal row size calculation error");
+
+   /* Don't expect this to ever happen: */
+   if (row_width == 0)
+      png_error(png_ptr, "internal row width error");
+
+   /* Preserve the last byte in cases where only part of it will be overwritten,
+    * the multiply below may overflow, we don't care because ANSI-C guarantees
+    * we get the low bits.
+    */
+   end_mask = (pixel_depth * row_width) & 7;
+   if (end_mask != 0)
    {
-      png_memcpy(row, png_ptr->row_buf + 1,
-          PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
+      /* end_ptr == NULL is a flag to say do nothing */
+      end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1;
+      end_byte = *end_ptr;
+#     ifdef PNG_READ_PACKSWAP_SUPPORTED
+         if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */
+            end_mask = 0xff << end_mask;
+
+         else /* big-endian byte */
+#     endif
+         end_mask = 0xff >> end_mask;
+      /* end_mask is now the bits to *keep* from the destination row */
    }
 
-   else
+   /* For non-interlaced images this reduces to a png_memcpy(). A png_memcpy()
+    * will also happen if interlacing isn't supported or if the application
+    * does not call png_set_interlace_handling().  In the latter cases the
+    * caller just gets a sequence of the unexpanded rows from each interlace
+    * pass.
+    */
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+   if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) &&
+      pass < 6 && (display == 0 ||
+      /* The following copies everything for 'display' on passes 0, 2 and 4. */
+      (display == 1 && (pass & 1) != 0)))
    {
-      switch (png_ptr->row_info.pixel_depth)
-      {
-         case 1:
-         {
-            png_bytep sp = png_ptr->row_buf + 1;
-            png_bytep dp = row;
-            int s_inc, s_start, s_end;
-            int m = 0x80;
-            int shift;
-            png_uint_32 i;
-            png_uint_32 row_width = png_ptr->width;
-
-#ifdef PNG_READ_PACKSWAP_SUPPORTED
-            if (png_ptr->transformations & PNG_PACKSWAP)
-            {
-                s_start = 0;
-                s_end = 7;
-                s_inc = 1;
-            }
+      /* Narrow images may have no bits in a pass; the caller should handle
+       * this, but this test is cheap:
+       */
+      if (row_width <= PNG_PASS_START_COL(pass))
+         return;
 
-            else
-#endif
-            {
-                s_start = 7;
-                s_end = 0;
-                s_inc = -1;
-            }
+      if (pixel_depth < 8)
+      {
+         /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit
+          * into 32 bits, then a single loop over the bytes using the four byte
+          * values in the 32-bit mask can be used.  For the 'display' option the
+          * expanded mask may also not require any masking within a byte.  To
+          * make this work the PACKSWAP option must be taken into account - it
+          * simply requires the pixels to be reversed in each byte.
+          *
+          * The 'regular' case requires a mask for each of the first 6 passes,
+          * the 'display' case does a copy for the even passes in the range
+          * 0..6.  This has already been handled in the test above.
+          *
+          * The masks are arranged as four bytes with the first byte to use in
+          * the lowest bits (little-endian) regardless of the order (PACKSWAP or
+          * not) of the pixels in each byte.
+          *
+          * NOTE: the whole of this logic depends on the caller of this function
+          * only calling it on rows appropriate to the pass.  This function only
+          * understands the 'x' logic; the 'y' logic is handled by the caller.
+          *
+          * The following defines allow generation of compile time constant bit
+          * masks for each pixel depth and each possibility of swapped or not
+          * swapped bytes.  Pass 'p' is in the range 0..6; 'x', a pixel index,
+          * is in the range 0..7; and the result is 1 if the pixel is to be
+          * copied in the pass, 0 if not.  'S' is for the sparkle method, 'B'
+          * for the block method.
+          *
+          * With some compilers a compile time expression of the general form:
+          *
+          *    (shift >= 32) ? (a >> (shift-32)) : (b >> shift)
+          *
+          * Produces warnings with values of 'shift' in the range 33 to 63
+          * because the right hand side of the ?: expression is evaluated by
+          * the compiler even though it isn't used.  Microsoft Visual C (various
+          * versions) and the Intel C compiler are known to do this.  To avoid
+          * this the following macros are used in 1.5.6.  This is a temporary
+          * solution to avoid destabilizing the code during the release process.
+          */
+#        if PNG_USE_COMPILE_TIME_MASKS
+#           define PNG_LSR(x,s) ((x)>>((s) & 0x1f))
+#           define PNG_LSL(x,s) ((x)<<((s) & 0x1f))
+#        else
+#           define PNG_LSR(x,s) ((x)>>(s))
+#           define PNG_LSL(x,s) ((x)<<(s))
+#        endif
+#        define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\
+           PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1)
+#        define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\
+           PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1)
+
+         /* Return a mask for pass 'p' pixel 'x' at depth 'd'.  The mask is
+          * little endian - the first pixel is at bit 0 - however the extra
+          * parameter 's' can be set to cause the mask position to be swapped
+          * within each byte, to match the PNG format.  This is done by XOR of
+          * the shift with 7, 6 or 4 for bit depths 1, 2 and 4.
+          */
+#        define PIXEL_MASK(p,x,d,s) \
+            (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0))))
 
-            shift = s_start;
+         /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask.
+          */
+#        define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
+#        define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0)
 
-            for (i = 0; i < row_width; i++)
-            {
-               if (m & mask)
-               {
-                  int value;
+         /* Combine 8 of these to get the full mask.  For the 1-bpp and 2-bpp
+          * cases the result needs replicating, for the 4-bpp case the above
+          * generates a full 32 bits.
+          */
+#        define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1)))
 
-                  value = (*sp >> shift) & 0x01;
-                  *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
-                  *dp |= (png_byte)(value << shift);
-               }
+#        define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\
+            S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\
+            S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d)
 
-               if (shift == s_end)
-               {
-                  shift = s_start;
-                  sp++;
-                  dp++;
-               }
+#        define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\
+            B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\
+            B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d)
 
-               else
-                  shift += s_inc;
+#if PNG_USE_COMPILE_TIME_MASKS
+         /* Utility macros to construct all the masks for a depth/swap
+          * combination.  The 's' parameter says whether the format is PNG
+          * (big endian bytes) or not.  Only the three odd-numbered passes are
+          * required for the display/block algorithm.
+          */
+#        define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\
+            S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }
 
-               if (m == 1)
-                  m = 0x80;
+#        define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) }
 
-               else
-                  m >>= 1;
-            }
-            break;
-         }
+#        define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
 
-         case 2:
+         /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and
+          * then pass:
+          */
+         static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] =
          {
-            png_bytep sp = png_ptr->row_buf + 1;
-            png_bytep dp = row;
-            int s_start, s_end, s_inc;
-            int m = 0x80;
-            int shift;
-            png_uint_32 i;
-            png_uint_32 row_width = png_ptr->width;
-            int value;
+            /* Little-endian byte masks for PACKSWAP */
+            { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) },
+            /* Normal (big-endian byte) masks - PNG format */
+            { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) }
+         };
+
+         /* display_mask has only three entries for the odd passes, so index by
+          * pass>>1.
+          */
+         static PNG_CONST png_uint_32 display_mask[2][3][3] =
+         {
+            /* Little-endian byte masks for PACKSWAP */
+            { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) },
+            /* Normal (big-endian byte) masks - PNG format */
+            { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) }
+         };
+
+#        define MASK(pass,depth,display,png)\
+            ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\
+               row_mask[png][DEPTH_INDEX(depth)][pass])
+
+#else /* !PNG_USE_COMPILE_TIME_MASKS */
+         /* This is the runtime alternative: it seems unlikely that this will
+          * ever be either smaller or faster than the compile time approach.
+          */
+#        define MASK(pass,depth,display,png)\
+            ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png))
+#endif /* !PNG_USE_COMPILE_TIME_MASKS */
+
+         /* Use the appropriate mask to copy the required bits.  In some cases
+          * the byte mask will be 0 or 0xff, optimize these cases.  row_width is
+          * the number of pixels, but the code copies bytes, so it is necessary
+          * to special case the end.
+          */
+         png_uint_32 pixels_per_byte = 8 / pixel_depth;
+         png_uint_32 mask;
 
-#ifdef PNG_READ_PACKSWAP_SUPPORTED
+#        ifdef PNG_READ_PACKSWAP_SUPPORTED
             if (png_ptr->transformations & PNG_PACKSWAP)
-            {
-               s_start = 0;
-               s_end = 6;
-               s_inc = 2;
-            }
+               mask = MASK(pass, pixel_depth, display, 0);
 
             else
-#endif
+#        endif
+            mask = MASK(pass, pixel_depth, display, 1);
+
+         for (;;)
+         {
+            png_uint_32 m;
+
+            /* It doesn't matter in the following if png_uint_32 has more than
+             * 32 bits because the high bits always match those in m<<24; it is,
+             * however, essential to use OR here, not +, because of this.
+             */
+            m = mask;
+            mask = (m >> 8) | (m << 24); /* rotate right to good compilers */
+            m &= 0xff;
+
+            if (m != 0) /* something to copy */
             {
-               s_start = 6;
-               s_end = 0;
-               s_inc = -2;
+               if (m != 0xff)
+                  *dp = (png_byte)((*dp & ~m) | (*sp & m));
+               else
+                  *dp = *sp;
             }
 
-            shift = s_start;
+            /* NOTE: this may overwrite the last byte with garbage if the image
+             * is not an exact number of bytes wide; libpng has always done
+             * this.
+             */
+            if (row_width <= pixels_per_byte)
+               break; /* May need to restore part of the last byte */
 
-            for (i = 0; i < row_width; i++)
-            {
-               if (m & mask)
-               {
-                  value = (*sp >> shift) & 0x03;
-                  *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
-                  *dp |= (png_byte)(value << shift);
-               }
+            row_width -= pixels_per_byte;
+            ++dp;
+            ++sp;
+         }
+      }
 
-               if (shift == s_end)
-               {
-                  shift = s_start;
-                  sp++;
-                  dp++;
-               }
+      else /* pixel_depth >= 8 */
+      {
+         unsigned int bytes_to_copy, bytes_to_jump;
 
-               else
-                  shift += s_inc;
+         /* Validate the depth - it must be a multiple of 8 */
+         if (pixel_depth & 7)
+            png_error(png_ptr, "invalid user transform pixel depth");
 
-               if (m == 1)
-                  m = 0x80;
+         pixel_depth >>= 3; /* now in bytes */
+         row_width *= pixel_depth;
 
-               else
-                  m >>= 1;
-            }
-            break;
+         /* Regardless of pass number the Adam 7 interlace always results in a
+          * fixed number of pixels to copy then to skip.  There may be a
+          * different number of pixels to skip at the start though.
+          */
+         {
+            unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth;
+
+            row_width -= offset;
+            dp += offset;
+            sp += offset;
          }
 
-         case 4:
+         /* Work out the bytes to copy. */
+         if (display)
          {
-            png_bytep sp = png_ptr->row_buf + 1;
-            png_bytep dp = row;
-            int s_start, s_end, s_inc;
-            int m = 0x80;
-            int shift;
-            png_uint_32 i;
-            png_uint_32 row_width = png_ptr->width;
-            int value;
+            /* When doing the 'block' algorithm the pixel in the pass gets
+             * replicated to adjacent pixels.  This is why the even (0,2,4,6)
+             * passes are skipped above - the entire expanded row is copied.
+             */
+            bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth;
 
-#ifdef PNG_READ_PACKSWAP_SUPPORTED
-            if (png_ptr->transformations & PNG_PACKSWAP)
-            {
-               s_start = 0;
-               s_end = 4;
-               s_inc = 4;
-            }
+            /* But don't allow this number to exceed the actual row width. */
+            if (bytes_to_copy > row_width)
+               bytes_to_copy = row_width;
+         }
 
-            else
-#endif
-            {
-               s_start = 4;
-               s_end = 0;
-               s_inc = -4;
-            }
-            shift = s_start;
+         else /* normal row; Adam7 only ever gives us one pixel to copy. */
+            bytes_to_copy = pixel_depth;
 
-            for (i = 0; i < row_width; i++)
-            {
-               if (m & mask)
+         /* In Adam7 there is a constant offset between where the pixels go. */
+         bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth;
+
+         /* And simply copy these bytes.  Some optimization is possible here,
+          * depending on the value of 'bytes_to_copy'.  Special case the low
+          * byte counts, which we know to be frequent.
+          *
+          * Notice that these cases all 'return' rather than 'break' - this
+          * avoids an unnecessary test on whether to restore the last byte
+          * below.
+          */
+         switch (bytes_to_copy)
+         {
+            case 1:
+               for (;;)
                {
-                  value = (*sp >> shift) & 0xf;
-                  *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
-                  *dp |= (png_byte)(value << shift);
+                  *dp = *sp;
+
+                  if (row_width <= bytes_to_jump)
+                     return;
+
+                  dp += bytes_to_jump;
+                  sp += bytes_to_jump;
+                  row_width -= bytes_to_jump;
                }
 
-               if (shift == s_end)
+            case 2:
+               /* There is a possibility of a partial copy at the end here; this
+                * slows the code down somewhat.
+                */
+               do
                {
-                  shift = s_start;
-                  sp++;
-                  dp++;
+                  dp[0] = sp[0], dp[1] = sp[1];
+
+                  if (row_width <= bytes_to_jump)
+                     return;
+
+                  sp += bytes_to_jump;
+                  dp += bytes_to_jump;
+                  row_width -= bytes_to_jump;
                }
+               while (row_width > 1);
 
-               else
-                  shift += s_inc;
+               /* And there can only be one byte left at this point: */
+               *dp = *sp;
+               return;
 
-               if (m == 1)
-                  m = 0x80;
+            case 3:
+               /* This can only be the RGB case, so each copy is exactly one
+                * pixel and it is not necessary to check for a partial copy.
+                */
+               for(;;)
+               {
+                  dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2];
 
-               else
-                  m >>= 1;
-            }
-            break;
-         }
+                  if (row_width <= bytes_to_jump)
+                     return;
 
-         default:
-         {
-            png_bytep sp = png_ptr->row_buf + 1;
-            png_bytep dp = row;
-            png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
-            png_uint_32 i;
-            png_uint_32 row_width = png_ptr->width;
-            png_byte m = 0x80;
+                  sp += bytes_to_jump;
+                  dp += bytes_to_jump;
+                  row_width -= bytes_to_jump;
+               }
 
-            for (i = 0; i < row_width; i++)
-            {
-               if (m & mask)
+            default:
+#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE
+               /* Check for double byte alignment and, if possible, use a
+                * 16-bit copy.  Don't attempt this for narrow images - ones that
+                * are less than an interlace panel wide.  Don't attempt it for
+                * wide bytes_to_copy either - use the png_memcpy there.
+                */
+               if (bytes_to_copy < 16 /*else use png_memcpy*/ &&
+                  png_isaligned(dp, png_uint_16) &&
+                  png_isaligned(sp, png_uint_16) &&
+                  bytes_to_copy % sizeof (png_uint_16) == 0 &&
+                  bytes_to_jump % sizeof (png_uint_16) == 0)
                {
-                  png_memcpy(dp, sp, pixel_bytes);
+                  /* Everything is aligned for png_uint_16 copies, but try for
+                   * png_uint_32 first.
+                   */
+                  if (png_isaligned(dp, png_uint_32) &&
+                     png_isaligned(sp, png_uint_32) &&
+                     bytes_to_copy % sizeof (png_uint_32) == 0 &&
+                     bytes_to_jump % sizeof (png_uint_32) == 0)
+                  {
+                     png_uint_32p dp32 = (png_uint_32p)dp;
+                     png_const_uint_32p sp32 = (png_const_uint_32p)sp;
+                     unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+                        sizeof (png_uint_32);
+
+                     do
+                     {
+                        size_t c = bytes_to_copy;
+                        do
+                        {
+                           *dp32++ = *sp32++;
+                           c -= sizeof (png_uint_32);
+                        }
+                        while (c > 0);
+
+                        if (row_width <= bytes_to_jump)
+                           return;
+
+                        dp32 += skip;
+                        sp32 += skip;
+                        row_width -= bytes_to_jump;
+                     }
+                     while (bytes_to_copy <= row_width);
+
+                     /* Get to here when the row_width truncates the final copy.
+                      * There will be 1-3 bytes left to copy, so don't try the
+                      * 16-bit loop below.
+                      */
+                     dp = (png_bytep)dp32;
+                     sp = (png_const_bytep)sp32;
+                     do
+                        *dp++ = *sp++;
+                     while (--row_width > 0);
+                     return;
+                  }
+
+                  /* Else do it in 16-bit quantities, but only if the size is
+                   * not too large.
+                   */
+                  else
+                  {
+                     png_uint_16p dp16 = (png_uint_16p)dp;
+                     png_const_uint_16p sp16 = (png_const_uint_16p)sp;
+                     unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+                        sizeof (png_uint_16);
+
+                     do
+                     {
+                        size_t c = bytes_to_copy;
+                        do
+                        {
+                           *dp16++ = *sp16++;
+                           c -= sizeof (png_uint_16);
+                        }
+                        while (c > 0);
+
+                        if (row_width <= bytes_to_jump)
+                           return;
+
+                        dp16 += skip;
+                        sp16 += skip;
+                        row_width -= bytes_to_jump;
+                     }
+                     while (bytes_to_copy <= row_width);
+
+                     /* End of row - 1 byte left, bytes_to_copy > row_width: */
+                     dp = (png_bytep)dp16;
+                     sp = (png_const_bytep)sp16;
+                     do
+                        *dp++ = *sp++;
+                     while (--row_width > 0);
+                     return;
+                  }
                }
+#endif /* PNG_ALIGN_ code */
 
-               sp += pixel_bytes;
-               dp += pixel_bytes;
+               /* The true default - use a png_memcpy: */
+               for (;;)
+               {
+                  png_memcpy(dp, sp, bytes_to_copy);
 
-               if (m == 1)
-                  m = 0x80;
+                  if (row_width <= bytes_to_jump)
+                     return;
 
-               else
-                  m >>= 1;
-            }
-            break;
+                  sp += bytes_to_jump;
+                  dp += bytes_to_jump;
+                  row_width -= bytes_to_jump;
+                  if (bytes_to_copy > row_width)
+                     bytes_to_copy = row_width;
+               }
          }
-      }
+
+         /* NOT REACHED*/
+      } /* pixel_depth >= 8 */
+
+      /* Here if pixel_depth < 8 to check 'end_ptr' below. */
    }
+   else
+#endif
+
+   /* If here then the switch above wasn't used so just png_memcpy the whole row
+    * from the temporary row buffer (notice that this overwrites the end of the
+    * destination row if it is a partial byte.)
+    */
+   png_memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width));
+
+   /* Restore the overwritten bits from the last byte if necessary. */
+   if (end_ptr != NULL)
+      *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask));
 }
 
 #ifdef PNG_READ_INTERLACING_SUPPORTED
 void /* PRIVATE */
-png_do_read_interlace(png_structp png_ptr)
+png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+   png_uint_32 transformations /* Because these may affect the byte layout */)
 {
-   png_row_infop row_info = &(png_ptr->row_info);
-   png_bytep row = png_ptr->row_buf + 1;
-   int pass = png_ptr->pass;
-   png_uint_32 transformations = png_ptr->transformations;
    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
    /* Offset to next interlace block */
-   PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+   static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
 
    png_debug(1, "in png_do_read_interlace");
    if (row != NULL && row_info != NULL)
@@ -3047,7 +3442,7 @@ png_do_read_interlace(png_structp png_ptr)
 
             for (i = 0; i < row_info->width; i++)
             {
-               png_byte v = (png_byte)((*sp >> sshift) & 0xf);
+               png_byte v = (png_byte)((*sp >> sshift) & 0x0f);
                int j;
 
                for (j = 0; j < jstop; j++)
@@ -3076,6 +3471,7 @@ png_do_read_interlace(png_structp png_ptr)
             }
             break;
          }
+
          default:
          {
             png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
@@ -3106,6 +3502,7 @@ png_do_read_interlace(png_structp png_ptr)
             break;
          }
       }
+
       row_info->width = final_width;
       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
    }
@@ -3115,134 +3512,202 @@ png_do_read_interlace(png_structp png_ptr)
 }
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
 
-void /* PRIVATE */
-png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
-    png_const_bytep prev_row, int filter)
+static void
+png_read_filter_row_sub(png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row)
 {
-   png_debug(1, "in png_read_filter_row");
-   png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter);
-   switch (filter)
+   png_size_t i;
+   png_size_t istop = row_info->rowbytes;
+   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
+   png_bytep rp = row + bpp;
+
+   PNG_UNUSED(prev_row)
+
+   for (i = bpp; i < istop; i++)
    {
-      case PNG_FILTER_VALUE_NONE:
-         break;
+      *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff);
+      rp++;
+   }
+}
 
-      case PNG_FILTER_VALUE_SUB:
-      {
-         png_size_t i;
-         png_size_t istop = row_info->rowbytes;
-         unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
-         png_bytep rp = row + bpp;
-         png_bytep lp = row;
+static void
+png_read_filter_row_up(png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row)
+{
+   png_size_t i;
+   png_size_t istop = row_info->rowbytes;
+   png_bytep rp = row;
+   png_const_bytep pp = prev_row;
 
-         for (i = bpp; i < istop; i++)
-         {
-            *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
-            rp++;
-         }
-         break;
-      }
-      case PNG_FILTER_VALUE_UP:
-      {
-         png_size_t i;
-         png_size_t istop = row_info->rowbytes;
-         png_bytep rp = row;
-         png_const_bytep pp = prev_row;
+   for (i = 0; i < istop; i++)
+   {
+      *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+      rp++;
+   }
+}
 
-         for (i = 0; i < istop; i++)
-         {
-            *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
-            rp++;
-         }
-         break;
-      }
-      case PNG_FILTER_VALUE_AVG:
-      {
-         png_size_t i;
-         png_bytep rp = row;
-         png_const_bytep pp = prev_row;
-         png_bytep lp = row;
-         unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
-         png_size_t istop = row_info->rowbytes - bpp;
-
-         for (i = 0; i < bpp; i++)
-         {
-            *rp = (png_byte)(((int)(*rp) +
-                ((int)(*pp++) / 2 )) & 0xff);
+static void
+png_read_filter_row_avg(png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row)
+{
+   png_size_t i;
+   png_bytep rp = row;
+   png_const_bytep pp = prev_row;
+   unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
+   png_size_t istop = row_info->rowbytes - bpp;
 
-            rp++;
-         }
+   for (i = 0; i < bpp; i++)
+   {
+      *rp = (png_byte)(((int)(*rp) +
+         ((int)(*pp++) / 2 )) & 0xff);
 
-         for (i = 0; i < istop; i++)
-         {
-            *rp = (png_byte)(((int)(*rp) +
-                (int)(*pp++ + *lp++) / 2 ) & 0xff);
+      rp++;
+   }
 
-            rp++;
-         }
-         break;
-      }
-      case PNG_FILTER_VALUE_PAETH:
-      {
-         png_size_t i;
-         png_bytep rp = row;
-         png_const_bytep pp = prev_row;
-         png_bytep lp = row;
-         png_const_bytep cp = prev_row;
-         unsigned int bpp = (row_info->pixel_depth + 7) >> 3;
-         png_size_t istop=row_info->rowbytes - bpp;
-
-         for (i = 0; i < bpp; i++)
-         {
-            *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
-            rp++;
-         }
+   for (i = 0; i < istop; i++)
+   {
+      *rp = (png_byte)(((int)(*rp) +
+         (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff);
 
-         for (i = 0; i < istop; i++)   /* Use leftover rp,pp */
-         {
-            int a, b, c, pa, pb, pc, p;
+      rp++;
+   }
+}
 
-            a = *lp++;
-            b = *pp++;
-            c = *cp++;
+static void
+png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row)
+{
+   png_bytep rp_end = row + row_info->rowbytes;
+   int a, c;
 
-            p = b - c;
-            pc = a - c;
+   /* First pixel/byte */
+   c = *prev_row++;
+   a = *row + c;
+   *row++ = (png_byte)a;
 
-#ifdef PNG_USE_ABS
-            pa = abs(p);
-            pb = abs(pc);
-            pc = abs(p + pc);
-#else
-            pa = p < 0 ? -p : p;
-            pb = pc < 0 ? -pc : pc;
-            pc = (p + pc) < 0 ? -(p + pc) : p + pc;
-#endif
+   /* Remainder */
+   while (row < rp_end)
+   {
+      int b, pa, pb, pc, p;
 
-            /*
-               if (pa <= pb && pa <= pc)
-                  p = a;
+      a &= 0xff; /* From previous iteration or start */
+      b = *prev_row++;
 
-               else if (pb <= pc)
-                  p = b;
+      p = b - c;
+      pc = a - c;
 
-               else
-                  p = c;
-             */
+#     ifdef PNG_USE_ABS
+         pa = abs(p);
+         pb = abs(pc);
+         pc = abs(p + pc);
+#     else
+         pa = p < 0 ? -p : p;
+         pb = pc < 0 ? -pc : pc;
+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#     endif
 
-            p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
+      /* Find the best predictor, the least of pa, pb, pc favoring the earlier
+       * ones in the case of a tie.
+       */
+      if (pb < pa) pa = pb, a = b;
+      if (pc < pa) a = c;
 
-            *rp = (png_byte)(((int)(*rp) + p) & 0xff);
-            rp++;
-         }
-         break;
-      }
-      default:
-         png_error(png_ptr, "Ignoring bad adaptive filter type");
-         /*NOT REACHED */
-         break;
+      /* Calculate the current pixel in a, and move the previous row pixel to c
+       * for the next time round the loop
+       */
+      c = b;
+      a += *row;
+      *row++ = (png_byte)a;
    }
 }
 
+static void
+png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row)
+{
+   int bpp = (row_info->pixel_depth + 7) >> 3;
+   png_bytep rp_end = row + bpp;
+
+   /* Process the first pixel in the row completely (this is the same as 'up'
+    * because there is only one candidate predictor for the first row).
+    */
+   while (row < rp_end)
+   {
+      int a = *row + *prev_row++;
+      *row++ = (png_byte)a;
+   }
+
+   /* Remainder */
+   rp_end += row_info->rowbytes - bpp;
+
+   while (row < rp_end)
+   {
+      int a, b, c, pa, pb, pc, p;
+
+      c = *(prev_row - bpp);
+      a = *(row - bpp);
+      b = *prev_row++;
+
+      p = b - c;
+      pc = a - c;
+
+#     ifdef PNG_USE_ABS
+         pa = abs(p);
+         pb = abs(pc);
+         pc = abs(p + pc);
+#     else
+         pa = p < 0 ? -p : p;
+         pb = pc < 0 ? -pc : pc;
+         pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#     endif
+
+      if (pb < pa) pa = pb, a = b;
+      if (pc < pa) a = c;
+
+      c = b;
+      a += *row;
+      *row++ = (png_byte)a;
+   }
+}
+
+static void
+png_init_filter_functions(png_structp pp)
+{
+   unsigned int bpp = (pp->pixel_depth + 7) >> 3;
+
+   pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub;
+   pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up;
+   pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg;
+   if (bpp == 1)
+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+         png_read_filter_row_paeth_1byte_pixel;
+   else
+      pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+         png_read_filter_row_paeth_multibyte_pixel;
+
+#ifdef PNG_FILTER_OPTIMIZATIONS
+   /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to
+    * call to install hardware optimizations for the above functions; simply
+    * replace whatever elements of the pp->read_filter[] array with a hardware
+    * specific (or, for that matter, generic) optimization.
+    *
+    * To see an example of this examine what configure.ac does when
+    * --enable-arm-neon is specified on the command line.
+    */
+   PNG_FILTER_OPTIMIZATIONS(pp, bpp);
+#endif
+}
+
+void /* PRIVATE */
+png_read_filter_row(png_structp pp, png_row_infop row_info, png_bytep row,
+   png_const_bytep prev_row, int filter)
+{
+   if (pp->read_filter[0] == NULL)
+      png_init_filter_functions(pp);
+   if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
+      pp->read_filter[filter-1](row_info, row, prev_row);
+}
+
 #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
 void /* PRIVATE */
 png_read_finish_row(png_structp png_ptr)
@@ -3251,16 +3716,16 @@ png_read_finish_row(png_structp png_ptr)
    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 
    /* Start of interlace block */
-   PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
 
    /* Offset to next interlace block */
-   PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
 
    /* Start of interlace block in the y direction */
-   PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
 
    /* Offset to next interlace block in the y direction */
-   PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
 
    png_debug(1, "in png_read_finish_row");
@@ -3273,6 +3738,9 @@ png_read_finish_row(png_structp png_ptr)
    {
       png_ptr->row_number = 0;
 
+      /* TO DO: don't do this if prev_row isn't needed (requires
+       * read-ahead of the next row's filter byte.
+       */
       png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
 
       do
@@ -3307,7 +3775,6 @@ png_read_finish_row(png_structp png_ptr)
 
    if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
    {
-      PNG_IDAT;
       char extra;
       int ret;
 
@@ -3322,7 +3789,7 @@ png_read_finish_row(png_structp png_ptr)
             {
                png_crc_finish(png_ptr, 0);
                png_ptr->idat_size = png_read_chunk_header(png_ptr);
-               if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+               if (png_ptr->chunk_name != png_IDAT)
                   png_error(png_ptr, "Not enough image data");
             }
 
@@ -3381,16 +3848,16 @@ png_read_start_row(png_structp png_ptr)
    /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
 
    /* Start of interlace block */
-   PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+   static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
 
    /* Offset to next interlace block */
-   PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+   static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
 
    /* Start of interlace block in the y direction */
-   PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+   static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
 
    /* Offset to next interlace block in the y direction */
-   PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+   static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
 #endif
 
    int max_pixel_depth;
@@ -3398,7 +3865,9 @@ png_read_start_row(png_structp png_ptr)
 
    png_debug(1, "in png_read_start_row");
    png_ptr->zstream.avail_in = 0;
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
    png_init_read_transformations(png_ptr);
+#endif
 #ifdef PNG_READ_INTERLACING_SUPPORTED
    if (png_ptr->interlaced)
    {
@@ -3424,6 +3893,16 @@ png_read_start_row(png_structp png_ptr)
 
    max_pixel_depth = png_ptr->pixel_depth;
 
+   /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of
+    * calculations to calculate the final pixel depth, then
+    * png_do_read_transforms actually does the transforms.  This means that the
+    * code which effectively calculates this value is actually repeated in three
+    * separate places.  They must all match.  Innocent changes to the order of
+    * transformations can and will break libpng in a way that causes memory
+    * overwrites.
+    *
+    * TODO: fix this.
+    */
 #ifdef PNG_READ_PACK_SUPPORTED
    if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
       max_pixel_depth = 8;
@@ -3482,10 +3961,7 @@ png_read_start_row(png_structp png_ptr)
 #ifdef PNG_READ_FILLER_SUPPORTED
    if (png_ptr->transformations & (PNG_FILLER))
    {
-      if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
-         max_pixel_depth = 32;
-
-      else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+      if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
       {
          if (max_pixel_depth <= 8)
             max_pixel_depth = 16;
@@ -3494,7 +3970,8 @@ png_read_start_row(png_structp png_ptr)
             max_pixel_depth = 32;
       }
 
-      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+      else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
+         png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
       {
          if (max_pixel_depth <= 32)
             max_pixel_depth = 32;
@@ -3548,14 +4025,20 @@ png_read_start_row(png_structp png_ptr)
 defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
    if (png_ptr->transformations & PNG_USER_TRANSFORM)
    {
-      int user_pixel_depth = png_ptr->user_transform_depth*
+      int user_pixel_depth = png_ptr->user_transform_depth *
          png_ptr->user_transform_channels;
 
       if (user_pixel_depth > max_pixel_depth)
-         max_pixel_depth=user_pixel_depth;
+         max_pixel_depth = user_pixel_depth;
    }
 #endif
 
+   /* This value is stored in png_struct and double checked in the row read
+    * code.
+    */
+   png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth;
+   png_ptr->transformed_pixel_depth = 0; /* calculated on demand */
+
    /* Align the width on the next larger 8 pixels.  Mainly used
     * for interlacing
     */
@@ -3574,28 +4057,39 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
    if (row_bytes + 48 > png_ptr->old_big_row_buf_size)
    {
      png_free(png_ptr, png_ptr->big_row_buf);
+     png_free(png_ptr, png_ptr->big_prev_row);
 
      if (png_ptr->interlaced)
         png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr,
             row_bytes + 48);
 
      else
-        png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr,
-            row_bytes + 48);
+        png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
 
-     png_ptr->old_big_row_buf_size = row_bytes + 48;
+     png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48);
 
 #ifdef PNG_ALIGNED_MEMORY_SUPPORTED
      /* Use 16-byte aligned memory for row_buf with at least 16 bytes
-      * of padding before and after row_buf.
+      * of padding before and after row_buf; treat prev_row similarly.
+      * NOTE: the alignment is to the start of the pixels, one beyond the start
+      * of the buffer, because of the filter byte.  Prior to libpng 1.5.6 this
+      * was incorrect; the filter byte was aligned, which had the exact
+      * opposite effect of that intended.
       */
-     png_ptr->row_buf = png_ptr->big_row_buf + 32 -
-         (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F);
+     {
+        png_bytep temp = png_ptr->big_row_buf + 32;
+        int extra = (int)((temp - (png_bytep)0) & 0x0f);
+        png_ptr->row_buf = temp - extra - 1/*filter byte*/;
+
+        temp = png_ptr->big_prev_row + 32;
+        extra = (int)((temp - (png_bytep)0) & 0x0f);
+        png_ptr->prev_row = temp - extra - 1/*filter byte*/;
+     }
 
-     png_ptr->old_big_row_buf_size = row_bytes + 48;
 #else
-     /* Use 32 bytes of padding before and 16 bytes after row_buf. */
-     png_ptr->row_buf = png_ptr->big_row_buf + 32;
+     /* Use 31 bytes of padding before and 17 bytes after row_buf. */
+     png_ptr->row_buf = png_ptr->big_row_buf + 31;
+     png_ptr->prev_row = png_ptr->big_prev_row + 31;
 #endif
      png_ptr->old_big_row_buf_size = row_bytes + 48;
    }
@@ -3608,15 +4102,6 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
    if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1))
       png_error(png_ptr, "Row has too many bytes to allocate in memory");
 
-   if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size)
-   {
-      png_free(png_ptr, png_ptr->prev_row);
-
-      png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
-
-      png_ptr->old_prev_row_size = png_ptr->rowbytes + 1;
-   }
-
    png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
 
    png_debug1(3, "width = %u,", png_ptr->width);