mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	This removes the side-effect on the png_struct palette of calling png_set_PLTE or png_set_tRNS. NOTE: this is a quiet API change, it was possible before to alter the palette on a PNG image by using png_set_PLTE, but this was unintended and inconsistent with the other png_set APIs. Fix a bug in palette index checking; png_struct::num_palette could, in principle, get changed by the transformations (e.g. png_set_quantize) and this would invalidate the check. The palette checking init function now makes a copy of png_struct::num_palette. Fix a bug in pngvalid error handling. A png_error in png_write_info is not continuable (a valid image cannot necessarily be written afterward) because the png_error aborts the write of subsequent pre-IDAT chunks. In particular an abort as a result of a bogus colorspace information (gAMA, cHRM, sBIT etc) prevents the write of the PLTE chunk. Signed-off-by: John Bowler <jbowler@acm.org>
		
			
				
	
	
		
			3770 lines
		
	
	
		
			113 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3770 lines
		
	
	
		
			113 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
 | 
						|
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
 | 
						|
 *
 | 
						|
 * Last changed in libpng 1.6.17 [(PENDING RELEASE)]
 | 
						|
 * Copyright (c) 1998-2015 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.)
 | 
						|
 *
 | 
						|
 * This code is released under the libpng license.
 | 
						|
 * For conditions of distribution and use, see the disclaimer
 | 
						|
 * and license in png.h
 | 
						|
 */
 | 
						|
#include "pngpriv.h"
 | 
						|
#define PNG_SRC_FILE PNG_SRC_FILE_pngtrans
 | 
						|
 | 
						|
#ifdef _XOPEN_SOURCE
 | 
						|
#  include <unistd.h>
 | 
						|
#endif /* for swab */
 | 
						|
 | 
						|
/* Memory format enquiries */
 | 
						|
#ifdef PNG_GAMMA_SUPPORTED
 | 
						|
static png_fixed_point
 | 
						|
memory_gamma(png_const_structrp png_ptr)
 | 
						|
{
 | 
						|
#  ifdef PNG_READ_GAMMA_SUPPORTED
 | 
						|
#     ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
            return png_ptr->row_gamma;
 | 
						|
#     endif /* TRANSFORM_MECH */
 | 
						|
#  endif /* READ_GAMMA */
 | 
						|
 | 
						|
   /* Else either no READ_GAMMA support or this is a write struct; in both
 | 
						|
    * cases there are no gamma transforms.  In the write case the set of the
 | 
						|
    * gamma in the info may not have been copied to the png_struct.
 | 
						|
    */
 | 
						|
#  if defined(PNG_GAMMA_SUPPORTED) && defined(PNG_READ_SUPPORTED)
 | 
						|
      if ((png_ptr->colorspace.flags &
 | 
						|
            (PNG_COLORSPACE_INVALID|PNG_COLORSPACE_HAVE_GAMMA)) ==
 | 
						|
         PNG_COLORSPACE_HAVE_GAMMA)
 | 
						|
         return png_ptr->colorspace.gamma;
 | 
						|
#  else /* !(GAMMA && READ) */
 | 
						|
      PNG_UNUSED(png_ptr)
 | 
						|
#  endif /* !(GAMMA && READ) */
 | 
						|
 | 
						|
   /* '0' means the value is not know: */
 | 
						|
   return 0;
 | 
						|
}
 | 
						|
#endif /* GAMMA */
 | 
						|
 | 
						|
unsigned int PNGAPI
 | 
						|
png_memory_format(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* The in-memory format as a bitmask of PNG_FORMAT_FLAG_ values.  All the
 | 
						|
    * flags listed below are used.  If PNG_FORMAT_FLAG_INVALID is set the
 | 
						|
    * following caveats apply to the interpretation of PNG_FORMAT_FLAG_LINEAR:
 | 
						|
    *
 | 
						|
    *    The gamma may differ from the sRGB (!LINEAR) or 1.0 (LINEAR).  Call
 | 
						|
    *    png_memory_gamma to find the correct value.
 | 
						|
    *
 | 
						|
    *    The channel depth may differ from 8 (!LINEAR) or 16 (LINEAR).  Call
 | 
						|
    *    png_memory_channel_depth to find the correct value.
 | 
						|
    *
 | 
						|
    * It is only valid to call these APIS *after* either png_read_update_info
 | 
						|
    * or png_start_read_image on read or after the first row of an image has
 | 
						|
    * been written on write.
 | 
						|
    */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
         unsigned int format = png_ptr->row_format;
 | 
						|
#     else /* !TRANSFORM_MECH */
 | 
						|
         unsigned int format = PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type);
 | 
						|
#     endif /* !TRANSFORM_MECH */
 | 
						|
 | 
						|
      if (png_ptr->read_struct) /* else no way to find the gamma! */
 | 
						|
      {
 | 
						|
#        ifdef PNG_GAMMA_SUPPORTED
 | 
						|
#           ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
               unsigned int bit_depth = png_ptr->row_bit_depth;
 | 
						|
#           else /* !TRANSFORM_MECH */
 | 
						|
               unsigned int bit_depth = png_ptr->bit_depth;
 | 
						|
#           endif /* !TRANSFORM_MECH */
 | 
						|
 | 
						|
            /* Now work out whether this is a valid simplified API format. */
 | 
						|
            switch (bit_depth)
 | 
						|
            {
 | 
						|
               case 8U:
 | 
						|
                  {
 | 
						|
                     png_fixed_point gamma = memory_gamma(png_ptr);
 | 
						|
 | 
						|
                     if (!PNG_GAMMA_IS_sRGB(gamma))
 | 
						|
                        format |= PNG_FORMAT_FLAG_INVALID;
 | 
						|
                  }
 | 
						|
                  break;
 | 
						|
 | 
						|
               case 16:
 | 
						|
                  if (memory_gamma(png_ptr) == PNG_GAMMA_LINEAR)
 | 
						|
                  {
 | 
						|
                     static const union
 | 
						|
                     {
 | 
						|
                        png_uint_16 u16;
 | 
						|
                        png_byte    u8[2];
 | 
						|
                     } sex = { 1U };
 | 
						|
 | 
						|
                     format |= PNG_FORMAT_FLAG_LINEAR;
 | 
						|
 | 
						|
                     /* But the memory layout of the 16-bit quantities must also
 | 
						|
                      * match; we need swapped data on LSB platforms.
 | 
						|
                      */
 | 
						|
                     if (sex.u8[0] == ((format & PNG_FORMAT_FLAG_SWAPPED) != 0))
 | 
						|
                        break; /* ok */
 | 
						|
                  }
 | 
						|
 | 
						|
                  /* FALL THROUGH*/
 | 
						|
               default: /* bit depth not supported for simplified API */
 | 
						|
                  format |= PNG_FORMAT_FLAG_INVALID;
 | 
						|
                  break;
 | 
						|
            }
 | 
						|
#        else /* !GAMMA */
 | 
						|
            /* We have no way of knowing if the gamma value matches that
 | 
						|
             * expected by the simplified API so mark the format as invalid:
 | 
						|
             */
 | 
						|
            format |= PNG_FORMAT_FLAG_INVALID;
 | 
						|
#        endif
 | 
						|
      } /* read_struct */
 | 
						|
 | 
						|
      return format;
 | 
						|
   }
 | 
						|
 | 
						|
   return 0;
 | 
						|
}
 | 
						|
 | 
						|
unsigned int PNGAPI png_memory_channel_depth(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* The actual depth of each channel in the image. */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
         return png_ptr->row_bit_depth;
 | 
						|
#     else
 | 
						|
         return png_ptr->bit_depth;
 | 
						|
#     endif
 | 
						|
   }
 | 
						|
 | 
						|
   return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_GAMMA_SUPPORTED
 | 
						|
png_fixed_point PNGAPI
 | 
						|
png_memory_gamma(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* The actual gamma of the image data, scaled by 100,000.  This is the
 | 
						|
    * encoding gamma, e.g. 1/2.2 for sRGB.  If the gamma is unknown this will
 | 
						|
    * return 0.
 | 
						|
    *
 | 
						|
    * On write this invariably returns 0; libpng does not change the gamma of
 | 
						|
    * the data on write.
 | 
						|
    *
 | 
						|
    * Note that this is not always the exact inverse of the 'screen gamma'
 | 
						|
    * passed to png_set_gamma; internal optimizations remove attempts to make
 | 
						|
    * small changes to the gamma value.  This function returns the actual
 | 
						|
    * output value.
 | 
						|
    */
 | 
						|
   return (png_ptr != NULL) ? memory_gamma(png_ptr) : 0;
 | 
						|
}
 | 
						|
#endif /* GAMMA */
 | 
						|
 | 
						|
/* These are general purpose APIs that deal with the row buffer format in both
 | 
						|
 * the read and write case.  The png_struct::row_* members describe the
 | 
						|
 * in-memory format of the image data based on the transformations requested by
 | 
						|
 * the application.
 | 
						|
 */
 | 
						|
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
png_voidp /* PRIVATE */
 | 
						|
png_transform_cast_check(png_const_structp png_ptr, unsigned int src_line,
 | 
						|
   png_transformp tr, size_t size)
 | 
						|
{
 | 
						|
   /* Given a pointer to a transform, 'tr' validate that the underlying derived
 | 
						|
    * class has size 'size' using the tr->size field and return the same
 | 
						|
    * pointer.  If there is a size mismatch the function does an affirm using
 | 
						|
    * the given line number.
 | 
						|
    */
 | 
						|
   if (tr->size != size)
 | 
						|
      png_affirm(png_ptr, param_deb("transform upcast") src_line);
 | 
						|
 | 
						|
   return tr;
 | 
						|
}
 | 
						|
 | 
						|
void /* PRIAVE */
 | 
						|
png_transform_free(png_const_structrp png_ptr, png_transformp *list)
 | 
						|
{
 | 
						|
   if (*list != NULL)
 | 
						|
   {
 | 
						|
      png_transform_free(png_ptr, &(*list)-> next);
 | 
						|
      if ((*list)->free != NULL)
 | 
						|
         (*list)->free(png_ptr, *list);
 | 
						|
      png_free(png_ptr, *list);
 | 
						|
      *list = NULL;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
/* Utility to initialize a png_transform_control for read or write. */
 | 
						|
void /* PRIVATE */
 | 
						|
png_init_transform_control(png_transform_controlp tc, png_structp png_ptr)
 | 
						|
{
 | 
						|
   png_byte bd; /* bit depth of the row */
 | 
						|
   png_byte cd; /* bit depth of color information */
 | 
						|
 | 
						|
   memset(tc, 0, sizeof *tc);
 | 
						|
   tc->png_ptr = png_ptr; /* ALIAS */
 | 
						|
   tc->sp = tc->dp = NULL;
 | 
						|
   tc->width = 0;
 | 
						|
 | 
						|
#  ifdef PNG_READ_GAMMA_SUPPORTED
 | 
						|
      /* The file gamma is set by png_set_gamma, as well as being read from the
 | 
						|
       * input PNG gAMA chunk, if present, we don't have a png_info so can't get
 | 
						|
       * the set_gAMA value but this doesn't matter because on read the gamma
 | 
						|
       * value is in png_struct::colorspace and on write it isn't used.
 | 
						|
       */
 | 
						|
      if ((png_ptr->colorspace.flags &
 | 
						|
            (PNG_COLORSPACE_INVALID|PNG_COLORSPACE_HAVE_GAMMA)) ==
 | 
						|
         PNG_COLORSPACE_HAVE_GAMMA)
 | 
						|
      {
 | 
						|
         tc->gamma = png_ptr->colorspace.gamma;
 | 
						|
         debug(tc->gamma > 0);
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
      {
 | 
						|
         /* There is no input gamma, so there should be no overall gamma
 | 
						|
          * correction going on.  This test works because the various things
 | 
						|
          * that set an output gamma also default the input gamma.
 | 
						|
          */
 | 
						|
         debug(png_ptr->row_gamma == 0);
 | 
						|
      }
 | 
						|
#  endif
 | 
						|
 | 
						|
   /* Validate bit depth and color type here */
 | 
						|
   cd = bd = png_ptr->bit_depth;
 | 
						|
 | 
						|
   switch (png_ptr->color_type)
 | 
						|
   {
 | 
						|
      case PNG_COLOR_TYPE_GRAY:
 | 
						|
         affirm(bd == 1U || bd == 2U || bd == 4U || bd == 8U || bd == 16U);
 | 
						|
         tc->format = 0U;
 | 
						|
         break;
 | 
						|
 | 
						|
      case PNG_COLOR_TYPE_PALETTE:
 | 
						|
         affirm(bd == 1U || bd == 2U || bd == 4U || bd == 8U);
 | 
						|
         tc->format = PNG_FORMAT_FLAG_COLORMAP | PNG_FORMAT_FLAG_COLOR;
 | 
						|
         cd = 8U;
 | 
						|
         break;
 | 
						|
 | 
						|
      case PNG_COLOR_TYPE_GRAY_ALPHA:
 | 
						|
         affirm(bd == 8U || bd == 16U);
 | 
						|
         tc->format = PNG_FORMAT_FLAG_ALPHA;
 | 
						|
         break;
 | 
						|
 | 
						|
      case PNG_COLOR_TYPE_RGB:
 | 
						|
         affirm(bd == 8U || bd == 16U);
 | 
						|
         tc->format = PNG_FORMAT_FLAG_COLOR;
 | 
						|
         break;
 | 
						|
 | 
						|
      case PNG_COLOR_TYPE_RGB_ALPHA:
 | 
						|
         affirm(bd == 8U || bd == 16U);
 | 
						|
         tc->format = PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_ALPHA;
 | 
						|
         break;
 | 
						|
 | 
						|
      default:
 | 
						|
         impossible("PNG color type");
 | 
						|
   }
 | 
						|
 | 
						|
   tc->bit_depth = bd;
 | 
						|
   tc->range = 0;
 | 
						|
 | 
						|
   /* Preset the sBIT data to full precision/handled. */
 | 
						|
   tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = tc->sBIT_A = cd;
 | 
						|
#  ifdef PNG_READ_sBIT_SUPPORTED
 | 
						|
      {
 | 
						|
         int handled = 1;
 | 
						|
 | 
						|
         if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
 | 
						|
         {
 | 
						|
            png_byte c = png_ptr->sig_bit.red;
 | 
						|
            if (c > 0 && c < cd)
 | 
						|
            {
 | 
						|
               tc->sBIT_R = c;
 | 
						|
               handled = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            c = png_ptr->sig_bit.green;
 | 
						|
            if (c > 0 && c < cd)
 | 
						|
            {
 | 
						|
               tc->sBIT_G = c;
 | 
						|
               handled = 0;
 | 
						|
            }
 | 
						|
 | 
						|
            c = png_ptr->sig_bit.blue;
 | 
						|
            if (c > 0 && c < cd)
 | 
						|
            {
 | 
						|
               tc->sBIT_B = c;
 | 
						|
               handled = 0;
 | 
						|
            }
 | 
						|
         }
 | 
						|
 | 
						|
         else /* grayscale */
 | 
						|
         {
 | 
						|
            png_byte c = png_ptr->sig_bit.gray;
 | 
						|
            if (c > 0 && c < cd)
 | 
						|
            {
 | 
						|
               tc->sBIT_R = tc->sBIT_G = tc->sBIT_B = c;
 | 
						|
               handled = 0;
 | 
						|
            }
 | 
						|
         }
 | 
						|
 | 
						|
         /* The palette-mapped format doesn't store alpha information, an
 | 
						|
          * omission in the spec that is difficult to fix.  Notice that
 | 
						|
          * 'handled' is not cleared below, this is because the alpha channel is
 | 
						|
          * always linear, so the sBIT_A value can always be treated as a
 | 
						|
          * precision value.
 | 
						|
          */
 | 
						|
         if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
 | 
						|
         {
 | 
						|
            png_byte c = png_ptr->sig_bit.alpha;
 | 
						|
            if (c > 0 && c < cd)
 | 
						|
               tc->sBIT_A = c;
 | 
						|
         }
 | 
						|
 | 
						|
         /* If 'handled' did not get cleared there is no sBIT information. */
 | 
						|
         if (handled)
 | 
						|
            tc->invalid_info = PNG_INFO_sBIT;
 | 
						|
      }
 | 
						|
#  else /* !READ_sBIT */
 | 
						|
      /* No sBIT information */
 | 
						|
      tc->invalid_info = PNG_INFO_sBIT;
 | 
						|
#  endif /* !READ_sBIT */
 | 
						|
}
 | 
						|
 | 
						|
png_transformp /*PRIVATE*/
 | 
						|
png_add_transform(png_structrp png_ptr, size_t size, png_transform_fn fn,
 | 
						|
   unsigned int order)
 | 
						|
{
 | 
						|
   /* Add a transform.  This is a minimal implementation; the order is just
 | 
						|
    * controlled by 'order', the result is a point to the new transform, or
 | 
						|
    * to an existing one if one was already in the list.
 | 
						|
    */
 | 
						|
   png_transformp *p = &png_ptr->transform_list;
 | 
						|
 | 
						|
   while (*p != NULL && (*p)->order < order)
 | 
						|
      p = &(*p)->next;
 | 
						|
 | 
						|
   if (size == 0)
 | 
						|
      size = sizeof (png_transform);
 | 
						|
 | 
						|
   else
 | 
						|
      affirm(size >= sizeof (png_transform));
 | 
						|
 | 
						|
   if (*p == NULL || (*p)->order > order)
 | 
						|
   {
 | 
						|
      png_transformp t;
 | 
						|
 | 
						|
      t = png_voidcast(png_transformp, png_malloc(png_ptr, size));
 | 
						|
      memset(t, 0, size); /* zeros out the extra data too */
 | 
						|
      /* *p comes after the new entry, t: */
 | 
						|
      t->next = *p;
 | 
						|
      t->fn = fn;
 | 
						|
      t->free = NULL;
 | 
						|
      t->order = order;
 | 
						|
      t->size = 0xFFFFU & size;
 | 
						|
      *p = t;
 | 
						|
      return t;
 | 
						|
   }
 | 
						|
 | 
						|
   else /* (*p)->order matches order, return *p */
 | 
						|
   {
 | 
						|
       affirm((*p)->fn == fn && (*p)->order == order && (*p)->size == size);
 | 
						|
       return *p;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
png_transformp /* PRIVATE */
 | 
						|
png_push_transform(png_structrp png_ptr, size_t size, png_transform_fn fn,
 | 
						|
   png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_transformp tr = *transform;
 | 
						|
   unsigned int order = tr->order;
 | 
						|
 | 
						|
   /* Basic loop detection: */
 | 
						|
   affirm(fn != NULL && tr->fn != fn);
 | 
						|
 | 
						|
   /* Move the following transforms up: */
 | 
						|
   {
 | 
						|
      unsigned int old_order = order;
 | 
						|
 | 
						|
      do
 | 
						|
      {
 | 
						|
         tr->order = ++old_order;
 | 
						|
         tr = tr->next;
 | 
						|
      }
 | 
						|
      while (tr != NULL && tr->order == old_order);
 | 
						|
 | 
						|
      affirm(tr == NULL || tr->order > old_order);
 | 
						|
   }
 | 
						|
 | 
						|
   *transform = png_add_transform(png_ptr, size, fn, order);
 | 
						|
 | 
						|
   if (tc != NULL)
 | 
						|
      fn(transform, tc);
 | 
						|
 | 
						|
   return *transform;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 | 
						|
static png_transformp
 | 
						|
png_find_transform(png_const_structrp png_ptr, unsigned int order)
 | 
						|
   /* Find a transform with the given order, or return NULL.  Currently only
 | 
						|
    * used here.
 | 
						|
    */
 | 
						|
{
 | 
						|
   png_transformp p = png_ptr->transform_list;
 | 
						|
 | 
						|
   for (;;)
 | 
						|
   {
 | 
						|
      if (p == NULL || p->order > order)
 | 
						|
         return NULL;
 | 
						|
 | 
						|
      if (p->order == order)
 | 
						|
         return p;
 | 
						|
 | 
						|
      p = p->next;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* USER_TRANSFORM_PTR */
 | 
						|
 | 
						|
static void
 | 
						|
remove_transform(png_const_structp png_ptr, png_transformp *transform)
 | 
						|
   /* Remove a transform on a running list */
 | 
						|
{
 | 
						|
   png_transformp tp = *transform;
 | 
						|
   png_transformp next = tp->next;
 | 
						|
 | 
						|
   *transform = next;
 | 
						|
   tp->next = NULL;
 | 
						|
   png_transform_free(png_ptr, &tp);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
void /* PRIVATE */
 | 
						|
png_remove_transform(png_const_structp png_ptr, png_transformp *transform)
 | 
						|
{
 | 
						|
   remove_transform(png_ptr, transform);
 | 
						|
}
 | 
						|
#endif /* READ_TRANSFORMS */
 | 
						|
 | 
						|
static unsigned int
 | 
						|
run_transform_list_forwards(png_transform_controlp tc, png_transformp *start,
 | 
						|
   png_transformp end/*NULL for whole list*/)
 | 
						|
   /* Called from the init code and below, the caller must initialize 'tc' */
 | 
						|
{
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
   unsigned int max_depth = PNG_TC_PIXEL_DEPTH(*tc);
 | 
						|
 | 
						|
   /* Caller guarantees that *start is non-NULL */
 | 
						|
   debug(*start != NULL);
 | 
						|
 | 
						|
   do
 | 
						|
   {
 | 
						|
      if ((*start)->fn != NULL)
 | 
						|
         (*start)->fn(start, tc);
 | 
						|
 | 
						|
      if ((*start)->fn == NULL) /* delete this transform */
 | 
						|
         remove_transform(png_ptr, start);
 | 
						|
 | 
						|
      else
 | 
						|
      {
 | 
						|
         /* Handle the initialization of the maximum pixel depth. */
 | 
						|
         unsigned int tc_depth = PNG_TC_PIXEL_DEPTH(*tc);
 | 
						|
 | 
						|
         if (tc_depth > max_depth)
 | 
						|
            max_depth = tc_depth;
 | 
						|
 | 
						|
         /* Advance to the next transform. */
 | 
						|
         start = &(*start)->next;
 | 
						|
      }
 | 
						|
   }
 | 
						|
   while (*start != NULL && *start != end);
 | 
						|
 | 
						|
   /* This only goes wrong if 'end' was non-NULL and not in the list: */
 | 
						|
   debug(*start == end);
 | 
						|
 | 
						|
   return max_depth;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
unsigned int /* PRIVATE */
 | 
						|
png_run_this_transform_list_forwards(png_transform_controlp tc,
 | 
						|
   png_transformp *start, png_transformp end)
 | 
						|
{
 | 
						|
   return run_transform_list_forwards(tc, start, end);
 | 
						|
}
 | 
						|
#endif /* READ_TRANSFORMS */
 | 
						|
 | 
						|
#ifdef PNG_READ_SUPPORTED
 | 
						|
unsigned int /* PRIVATE */
 | 
						|
png_run_transform_list_forwards(png_structp png_ptr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   if (png_ptr->transform_list != NULL)
 | 
						|
      return run_transform_list_forwards(tc, &png_ptr->transform_list, NULL);
 | 
						|
 | 
						|
   else
 | 
						|
      return PNG_PIXEL_DEPTH(*png_ptr);
 | 
						|
}
 | 
						|
#endif /* READ */
 | 
						|
 | 
						|
#ifdef PNG_WRITE_SUPPORTED /* only used from pngwrite.c */
 | 
						|
static unsigned int
 | 
						|
run_transform_list_backwards(png_transform_controlp tc, png_transformp *list)
 | 
						|
{
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
   unsigned int max_depth = 0;
 | 
						|
 | 
						|
   if ((*list)->next != NULL)
 | 
						|
      max_depth = run_transform_list_backwards(tc, &(*list)->next);
 | 
						|
 | 
						|
   /* Note that the above might change (*list)->next, but it can't change
 | 
						|
    * *list itself.
 | 
						|
    */
 | 
						|
   if ((*list)->fn != NULL)
 | 
						|
      (*list)->fn(list, tc);
 | 
						|
 | 
						|
   /* If that set 'fn' to NULL this transform must be removed; this is how
 | 
						|
    * (*list)->next gets changed in our caller:
 | 
						|
    */
 | 
						|
   if ((*list)->fn == NULL)
 | 
						|
      remove_transform(png_ptr, list);
 | 
						|
 | 
						|
   else
 | 
						|
   {
 | 
						|
      unsigned int depth = PNG_TC_PIXEL_DEPTH(*tc);
 | 
						|
 | 
						|
      if (depth > max_depth)
 | 
						|
         max_depth = depth;
 | 
						|
   }
 | 
						|
 | 
						|
   return max_depth;
 | 
						|
}
 | 
						|
 | 
						|
void /* PRIVATE */
 | 
						|
png_run_transform_list_backwards(png_structp png_ptr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   if (png_ptr->transform_list != NULL)
 | 
						|
   {
 | 
						|
      /* This doesn't take account of the base PNG depth, but that shouldn't
 | 
						|
       * matter, it's just a check:
 | 
						|
       */
 | 
						|
      unsigned int max_depth =
 | 
						|
         run_transform_list_backwards(tc, &png_ptr->transform_list);
 | 
						|
 | 
						|
      /* Better late than never (if this fires a memory overwrite has happened):
 | 
						|
       */
 | 
						|
      affirm(max_depth <= png_ptr->row_max_pixel_depth);
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* WRITE */
 | 
						|
 | 
						|
static unsigned int
 | 
						|
init_transform_mech(png_structrp png_ptr, png_transform_control *tc, int start)
 | 
						|
   /* Called each time to run the transform list once during initialization. */
 | 
						|
{
 | 
						|
   png_init_transform_control(tc, png_ptr);
 | 
						|
   tc->init = start ? PNG_TC_INIT_FORMAT : PNG_TC_INIT_FINAL;
 | 
						|
#  ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
         return png_read_init_transform_mech(png_ptr, tc);
 | 
						|
      else
 | 
						|
#  endif
 | 
						|
   return run_transform_list_forwards(tc, &png_ptr->transform_list, NULL);
 | 
						|
}
 | 
						|
#endif /* TRANSFORM_MECH */
 | 
						|
 | 
						|
#ifdef PNG_PALETTE_MAX_SUPPORTED
 | 
						|
static int
 | 
						|
set_palette_max(png_structrp png_ptr, png_transformp tr, unsigned int max,
 | 
						|
      unsigned int format_max)
 | 
						|
   /* Called whenever a new maximum pixel value is found */
 | 
						|
{
 | 
						|
   /* One of these must be true: */
 | 
						|
#  ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
      if (max >= tr->args && !png_ptr->palette_index_check_issued)
 | 
						|
      {
 | 
						|
#        ifdef PNG_READ_SUPPORTED
 | 
						|
#           ifdef PNG_WRITE_SUPPORTED
 | 
						|
               (png_ptr->read_struct ? png_chunk_benign_error : png_error)
 | 
						|
#           else /* !WRITE */
 | 
						|
               png_chunk_benign_error
 | 
						|
#           endif /* !WRITE */
 | 
						|
#        else /* !READ */
 | 
						|
            png_error
 | 
						|
#        endif /* !READ */
 | 
						|
            (png_ptr, "palette index too large");
 | 
						|
         png_ptr->palette_index_check_issued = 1;
 | 
						|
      }
 | 
						|
#  endif
 | 
						|
#  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
 | 
						|
      png_ptr->palette_index_max = png_check_bits(png_ptr, max, 9);
 | 
						|
#  endif
 | 
						|
 | 
						|
   if (max == format_max)
 | 
						|
   {
 | 
						|
      tr->fn = NULL; /* no point continuing once the max has been seen */
 | 
						|
      return 1; /* stop */
 | 
						|
   }
 | 
						|
 | 
						|
   return 0; /* keep going */
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
palette_max_1bpp(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   while (width >= 8)
 | 
						|
   {
 | 
						|
      if (*sp++) break;
 | 
						|
      width -= 8;
 | 
						|
   }
 | 
						|
 | 
						|
   if (width < 8)
 | 
						|
   {
 | 
						|
      if (width == 0 ||
 | 
						|
          (*sp & (((1U<<width)-1U) << (8-width))) == 0)
 | 
						|
         return; /* no '1' pixels */
 | 
						|
   }
 | 
						|
 | 
						|
   /* If the code reaches this point there is a set pixel */
 | 
						|
   (void)set_palette_max(tc->png_ptr, *tr, 1U, 1U);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
palette_max_2bpp(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
   unsigned int max = (*tr)->args; /* saved maximum */
 | 
						|
 | 
						|
   while (width > 0)
 | 
						|
   {
 | 
						|
      png_uint_32 input = 0U, test;
 | 
						|
      unsigned int new_max;
 | 
						|
 | 
						|
      /* This just skips 0 bytes: */
 | 
						|
      while (width > 0)
 | 
						|
      {
 | 
						|
         unsigned int next = *sp++;
 | 
						|
 | 
						|
         /* There may be partial pixels at the end, just remove the absent
 | 
						|
          * pixels with a right shift:
 | 
						|
          */
 | 
						|
         if (width >= 4)
 | 
						|
            width -= 4;
 | 
						|
         else
 | 
						|
            next >>= (4U-width) * 2U, width = 0;
 | 
						|
 | 
						|
         if (next)
 | 
						|
         {
 | 
						|
            input = (input << 8) | next;
 | 
						|
            if ((input & 0xFF000000U) != 0)
 | 
						|
               break;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      test = input & 0xAAAAAAAAU;
 | 
						|
 | 
						|
      if (test != 0)
 | 
						|
      {
 | 
						|
         if ((input & (test >> 1)) != 0)
 | 
						|
            new_max = 3U; /* both bits set in at least one pixel */
 | 
						|
 | 
						|
         else if (max < 2U)
 | 
						|
            new_max = 2U;
 | 
						|
 | 
						|
         else
 | 
						|
            continue; /* no change to max */
 | 
						|
      }
 | 
						|
 | 
						|
      else /* test is 0 */ if (input != 0 && max == 0)
 | 
						|
         new_max = 1U;
 | 
						|
 | 
						|
      else /* input is 0, or max is at least 1 */
 | 
						|
         continue;
 | 
						|
 | 
						|
      /* new_max is greater than max: */
 | 
						|
      if (set_palette_max(tc->png_ptr, *tr, new_max, 3U))
 | 
						|
         return;
 | 
						|
 | 
						|
      /* Record new_max: */
 | 
						|
      max = new_max;
 | 
						|
   }
 | 
						|
 | 
						|
   /* End of input, check the next line. */
 | 
						|
   (*tr)->args = max;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
palette_max_4bpp(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
   unsigned int max = (*tr)->args; /* saved maximum */
 | 
						|
 | 
						|
   while (width > 0)
 | 
						|
   {
 | 
						|
      unsigned int input = *sp++;
 | 
						|
 | 
						|
      if (width >= 2)
 | 
						|
         width -= 2;
 | 
						|
      else
 | 
						|
         input >>= 1, width = 0;
 | 
						|
 | 
						|
      if ((input & 0xFU) > max)
 | 
						|
         max = input & 0xFU;
 | 
						|
 | 
						|
      if (((input >> 4) & 0xFU) > max)
 | 
						|
         max = (input >> 4) & 0xFU;
 | 
						|
   }
 | 
						|
 | 
						|
   if (max > (*tr)->args)
 | 
						|
   {
 | 
						|
      if (set_palette_max(tc->png_ptr, *tr, max, 15U))
 | 
						|
         return;
 | 
						|
 | 
						|
      (*tr)->args = max;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
palette_max_8bpp(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
   unsigned int max = (*tr)->args; /* saved maximum */
 | 
						|
 | 
						|
   while (width > 0)
 | 
						|
   {
 | 
						|
      unsigned int input = *sp++;
 | 
						|
 | 
						|
      if (input > max)
 | 
						|
         max = input;
 | 
						|
 | 
						|
      --width;
 | 
						|
   }
 | 
						|
 | 
						|
   if (max > (*tr)->args)
 | 
						|
   {
 | 
						|
      if (set_palette_max(tc->png_ptr, *tr, max, 255U))
 | 
						|
         return;
 | 
						|
 | 
						|
      (*tr)->args = max;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
palette_max_init(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
 | 
						|
   {
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL)
 | 
						|
      {
 | 
						|
         /* Record the palette depth to check here: */
 | 
						|
         (*tr)->args = png_ptr->num_palette;
 | 
						|
 | 
						|
         switch (tc->bit_depth)
 | 
						|
         {
 | 
						|
            case 1: (*tr)->fn = palette_max_1bpp; break;
 | 
						|
            case 2: (*tr)->fn = palette_max_2bpp; break;
 | 
						|
            case 4: (*tr)->fn = palette_max_4bpp; break;
 | 
						|
            case 8: (*tr)->fn = palette_max_8bpp; break;
 | 
						|
            default:impossible("palette bit depth");
 | 
						|
         }
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   else
 | 
						|
      (*tr)->fn = NULL; /* not applicable */
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
#endif /* PALETTE_MAX */
 | 
						|
 | 
						|
#ifdef PNG_GET_PALETTE_MAX_SUPPORTED
 | 
						|
int PNGAPI
 | 
						|
png_get_palette_max(png_const_structrp png_ptr, png_const_inforp info_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL
 | 
						|
#     ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
         && !png_ptr->palette_index_check_disabled
 | 
						|
#     endif
 | 
						|
      )
 | 
						|
      return png_ptr->palette_index_max;
 | 
						|
 | 
						|
   /* This indicates to the caller that the information is not available: */
 | 
						|
   return -1;
 | 
						|
   PNG_UNUSED(info_ptr)
 | 
						|
}
 | 
						|
#endif /* GET_PALETTE_MAX */
 | 
						|
 | 
						|
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
   /* Whether to report invalid palette index; added at libng-1.5.10.
 | 
						|
    * It is possible for an indexed (color-type==3) PNG file to contain
 | 
						|
    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
 | 
						|
    * fewer entries than the image's bit-depth would allow. We recover
 | 
						|
    * from this gracefully by filling any incomplete palette with zeros
 | 
						|
    * (opaque black).  By default, when this occurs libpng will issue
 | 
						|
    * a benign error.  This API can be used to override that behavior.
 | 
						|
    */
 | 
						|
void PNGAPI
 | 
						|
png_set_check_for_invalid_index(png_structrp png_ptr, int enabled)
 | 
						|
{
 | 
						|
   /* This defaults to 0, therefore *on*: */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
#        ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
            png_ptr->palette_index_check_disabled = enabled <= 0;
 | 
						|
#        else /* !READ_CHECK_FOR_INVALID_INDEX */
 | 
						|
            png_app_error(png_ptr, "no read palette check support");
 | 
						|
#        endif /* !READ_CHECK_FOR_INVALID_INDEX */
 | 
						|
      else /* write struct */
 | 
						|
#        ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
            png_ptr->palette_index_check_disabled = enabled <= 0;
 | 
						|
#        else /* !WRITE_CHECK_FOR_INVALID_INDEX */
 | 
						|
            png_app_error(png_ptr, "no write palette check support");
 | 
						|
#        endif /* !WRITE_CHECK_FOR_INVALID_INDEX */
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* CHECK_FOR_INVALID_INDEX */
 | 
						|
 | 
						|
void /* PRIVATE */
 | 
						|
png_init_row_info(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* PNG pixels never exceed 64 bits in depth: */
 | 
						|
   const png_byte png_depth =
 | 
						|
      png_check_bits(png_ptr, PNG_PIXEL_DEPTH(*png_ptr), 7U);
 | 
						|
 | 
						|
#  ifdef PNG_TRANSFORM_MECH_SUPPORTED
 | 
						|
      /* The palette index check stuff is *on* automatically.  To handle this
 | 
						|
       * add it here, if it is supported.
 | 
						|
       */
 | 
						|
#     ifdef PNG_PALETTE_MAX_SUPPORTED
 | 
						|
         /* The logic here is a little complex because of the plethora of
 | 
						|
          * #defines controlling this stuff.
 | 
						|
          */
 | 
						|
         if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE/* fast escape */ && (
 | 
						|
#           if defined (PNG_READ_GET_PALETTE_MAX_SUPPORTED) ||\
 | 
						|
               defined (PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED)
 | 
						|
               (png_ptr->read_struct
 | 
						|
#              ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
                  && !png_ptr->palette_index_check_disabled)
 | 
						|
#              endif /* READ_CHECK_FOR_INVALID_INDEX */
 | 
						|
#           else /* no READ support */
 | 
						|
               0
 | 
						|
#           endif /* READ checks */
 | 
						|
            ||
 | 
						|
#           if defined (PNG_WRITE_GET_PALETTE_MAX_SUPPORTED) ||\
 | 
						|
               defined (PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
 | 
						|
               (!png_ptr->read_struct
 | 
						|
#              ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
 | 
						|
                  && !png_ptr->palette_index_check_disabled)
 | 
						|
#              endif /* WRITE_CHECK_FOR_INVALID_INDEX */
 | 
						|
#           else /* no WRITE support */
 | 
						|
               0
 | 
						|
#           endif /* WRITE checks */
 | 
						|
            ))
 | 
						|
            png_add_transform(png_ptr, 0/*size*/, palette_max_init,
 | 
						|
               PNG_TR_CHECK_PALETTE);
 | 
						|
#     endif
 | 
						|
 | 
						|
      /* Application transforms may change the format of the data or, when
 | 
						|
       * producing interlaced images, the number of pixels in a line.  This code
 | 
						|
       * determines the maximum pixel depth required and allows transformations
 | 
						|
       * a chance to initialize themselves.
 | 
						|
       */
 | 
						|
      if (png_ptr->transform_list != NULL)
 | 
						|
      {
 | 
						|
         png_transform_control tc;
 | 
						|
 | 
						|
         (void)init_transform_mech(png_ptr, &tc, 1/*start*/);
 | 
						|
 | 
						|
         png_ptr->row_format = png_check_bits(png_ptr, tc.format, PNG_RF_BITS);
 | 
						|
         affirm(tc.bit_depth <= 32);
 | 
						|
         png_ptr->row_bit_depth = png_check_bits(png_ptr, tc.bit_depth, 6);
 | 
						|
         png_ptr->row_range = png_check_bits(png_ptr, tc.range, 3);
 | 
						|
#        ifdef PNG_READ_GAMMA_SUPPORTED
 | 
						|
            png_ptr->row_gamma = tc.gamma;
 | 
						|
#        endif /* READ_GAMMA */
 | 
						|
 | 
						|
         /* The above may have cancelled all the transforms in the list. */
 | 
						|
         if (png_ptr->transform_list != NULL)
 | 
						|
         {
 | 
						|
            /* Run the transform list again, also forward, and accumulate the
 | 
						|
             * maximum pixel depth.  At this point the transforms can swap
 | 
						|
             * out their initialization code.
 | 
						|
             */
 | 
						|
            unsigned int max_depth =
 | 
						|
               init_transform_mech(png_ptr, &tc, 0/*final*/);
 | 
						|
 | 
						|
            /* init_transform_mech is expected to take the input depth into
 | 
						|
             * account:
 | 
						|
             */
 | 
						|
            debug(max_depth >= png_depth);
 | 
						|
            if (max_depth < png_depth)
 | 
						|
                max_depth = png_depth;
 | 
						|
            affirm(max_depth <= (png_ptr->read_struct ? 128U : 64U));
 | 
						|
 | 
						|
#           ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
               /* Set this now because it only gets resolved finally at this
 | 
						|
                * point.
 | 
						|
                */
 | 
						|
               png_ptr->invalid_info = tc.invalid_info;
 | 
						|
#           endif /* READ_TRANSFORMS */
 | 
						|
 | 
						|
            /* And check the transform fields: */
 | 
						|
            affirm(png_ptr->row_format == tc.format &&
 | 
						|
               png_ptr->row_range == tc.range &&
 | 
						|
               png_ptr->row_bit_depth == tc.bit_depth);
 | 
						|
#           ifdef PNG_READ_GAMMA_SUPPORTED
 | 
						|
               affirm(png_ptr->row_gamma == tc.gamma);
 | 
						|
#           endif /* READ_GAMMA */
 | 
						|
 | 
						|
            png_ptr->row_max_pixel_depth =
 | 
						|
               png_check_bits(png_ptr, max_depth, 8U);
 | 
						|
 | 
						|
            /* On 'read' input_depth is the PNG pixel depth and output_depth is
 | 
						|
             * the depth of the pixels passed to the application, but on 'write'
 | 
						|
             * the transform list is reversed so output_depth is the PNG depth
 | 
						|
             * and input_depth the application depth.
 | 
						|
             */
 | 
						|
            {
 | 
						|
               const png_byte app_depth =
 | 
						|
                  png_check_bits(png_ptr, PNG_TC_PIXEL_DEPTH(tc), 8U);
 | 
						|
 | 
						|
               affirm(app_depth <= max_depth);
 | 
						|
 | 
						|
               if (png_ptr->read_struct)
 | 
						|
               {
 | 
						|
                  png_ptr->row_input_pixel_depth = png_depth;
 | 
						|
                  png_ptr->row_output_pixel_depth = app_depth;
 | 
						|
               }
 | 
						|
 | 
						|
               else
 | 
						|
               {
 | 
						|
                  png_ptr->row_input_pixel_depth = app_depth;
 | 
						|
                  png_ptr->row_output_pixel_depth = png_depth;
 | 
						|
               }
 | 
						|
 | 
						|
               return; /* to skip the default settings below */
 | 
						|
            }
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      else /* png_ptr->transform_list == NULL */
 | 
						|
      {
 | 
						|
         png_ptr->row_format = png_check_bits(png_ptr,
 | 
						|
            PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type), PNG_RF_BITS);
 | 
						|
         png_ptr->row_bit_depth = png_check_bits(png_ptr, png_ptr->bit_depth,
 | 
						|
            6);
 | 
						|
         png_ptr->row_range = 0;
 | 
						|
#        ifdef PNG_READ_GAMMA_SUPPORTED
 | 
						|
            if ((png_ptr->colorspace.flags &
 | 
						|
                  (PNG_COLORSPACE_INVALID|PNG_COLORSPACE_HAVE_GAMMA)) ==
 | 
						|
                 PNG_COLORSPACE_HAVE_GAMMA)
 | 
						|
               png_ptr->row_gamma = png_ptr->colorspace.gamma;
 | 
						|
#        endif /* READ_GAMMA */
 | 
						|
#        ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
            png_ptr->invalid_info = 0U;
 | 
						|
#        endif /* READ_TRANSFORMS */
 | 
						|
      }
 | 
						|
#  endif /* TRANSFORM_MECH */
 | 
						|
 | 
						|
   /* We get here if there are no transforms therefore no change to the pixel
 | 
						|
    * bit depths.
 | 
						|
    */
 | 
						|
   png_ptr->row_output_pixel_depth = png_ptr->row_max_pixel_depth =
 | 
						|
      png_ptr->row_input_pixel_depth = png_depth;
 | 
						|
}
 | 
						|
 | 
						|
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
 | 
						|
    defined(PNG_WRITE_INTERLACING_SUPPORTED)
 | 
						|
int PNGAPI
 | 
						|
png_set_interlace_handling(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   png_debug(1, "in png_set_interlace handling");
 | 
						|
 | 
						|
   if (png_ptr != 0)
 | 
						|
   {
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
      {
 | 
						|
#        ifdef PNG_READ_INTERLACING_SUPPORTED
 | 
						|
            if (png_ptr->interlaced)
 | 
						|
            {
 | 
						|
               png_ptr->do_interlace = 1;
 | 
						|
               return PNG_INTERLACE_ADAM7_PASSES;
 | 
						|
            }
 | 
						|
 | 
						|
            return 1;
 | 
						|
#        else /* !READ_INTERLACING */
 | 
						|
            png_app_error(png_ptr, "no de-interlace support");
 | 
						|
            /* return 0 below */
 | 
						|
#        endif /* !READ_INTERLACING */
 | 
						|
      }
 | 
						|
 | 
						|
      else /* write */
 | 
						|
      {
 | 
						|
#        ifdef PNG_WRITE_INTERLACING_SUPPORTED
 | 
						|
            if (png_ptr->interlaced)
 | 
						|
            {
 | 
						|
               png_ptr->do_interlace = 1;
 | 
						|
               return PNG_INTERLACE_ADAM7_PASSES;
 | 
						|
            }
 | 
						|
 | 
						|
            return 1;
 | 
						|
#        else /* !WRITE_INTERLACING */
 | 
						|
            png_app_error(png_ptr, "no interlace support");
 | 
						|
            /* return 0 below */
 | 
						|
#        endif /* !WRITE_INTERLACING */
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   /* API CHANGE: 1.7.0: returns 0 if called with a NULL png_ptr */
 | 
						|
   return 0;
 | 
						|
}
 | 
						|
#endif /* READ_INTERLACING || WRITE_INTERLACING */
 | 
						|
 | 
						|
#ifdef PNG_MNG_READ_FEATURES_SUPPORTED
 | 
						|
/* Undoes intrapixel differencing, this is called immediately after the PNG
 | 
						|
 * filter has been undone.
 | 
						|
 */
 | 
						|
static void
 | 
						|
png_do_read_intrapixel_RGB8(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   /* TAKE CARE: dp and sp may be the same, in which case the assignments to *dp
 | 
						|
    * are overwriting sp[]
 | 
						|
    */
 | 
						|
   do
 | 
						|
   {
 | 
						|
      *dp++ = PNG_BYTE(sp[0] + sp[1]); /* red+green */
 | 
						|
      *dp++ = *++sp; /* green */
 | 
						|
      *dp++ = PNG_BYTE(sp[0] + sp[1]); /* green+blue */
 | 
						|
      sp += 2;
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_read_intrapixel_RGBA8(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   do
 | 
						|
   {
 | 
						|
      *dp++ = PNG_BYTE(sp[0] + sp[1]); /* red+green */
 | 
						|
      *dp++ = *++sp; /* green */
 | 
						|
      *dp++ = PNG_BYTE(sp[0] + sp[1]); /* green+blue */
 | 
						|
      sp += 2;
 | 
						|
      *dp++ = *sp++; /* alpha */
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_read_intrapixel_RGB16(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   /* The input consists of 16-bit values and, by examination of the code
 | 
						|
    * (please, someone, check; I didn't read the spec) the differencing is done
 | 
						|
    * against the 16-bit green value.
 | 
						|
    */
 | 
						|
   do
 | 
						|
   {
 | 
						|
      unsigned int red   = png_get_uint_16(sp + 0);
 | 
						|
      unsigned int green = png_get_uint_16(sp + 2);
 | 
						|
      unsigned int blue  = png_get_uint_16(sp + 4);
 | 
						|
      sp += 6;
 | 
						|
 | 
						|
      red  += green;
 | 
						|
      blue += green;
 | 
						|
 | 
						|
      *dp++ = PNG_BYTE(red >> 8);
 | 
						|
      *dp++ = PNG_BYTE(red);
 | 
						|
      *dp++ = PNG_BYTE(green >> 8);
 | 
						|
      *dp++ = PNG_BYTE(green);
 | 
						|
      *dp++ = PNG_BYTE(blue >> 8);
 | 
						|
      *dp++ = PNG_BYTE(blue);
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_read_intrapixel_RGBA16(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   /* As above but copy the alpha over too. */
 | 
						|
   do
 | 
						|
   {
 | 
						|
      unsigned int red   = png_get_uint_16(sp + 0);
 | 
						|
      unsigned int green = png_get_uint_16(sp + 2);
 | 
						|
      unsigned int blue  = png_get_uint_16(sp + 4);
 | 
						|
      sp += 6;
 | 
						|
 | 
						|
      red  += green;
 | 
						|
      blue += green;
 | 
						|
 | 
						|
      *dp++ = PNG_BYTE(red >> 8);
 | 
						|
      *dp++ = PNG_BYTE(red);
 | 
						|
      *dp++ = PNG_BYTE(green >> 8);
 | 
						|
      *dp++ = PNG_BYTE(green);
 | 
						|
      *dp++ = PNG_BYTE(blue >> 8);
 | 
						|
      *dp++ = PNG_BYTE(blue);
 | 
						|
      *dp++ = *sp++;
 | 
						|
      *dp++ = *sp++; /* alpha */
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_init_read_intrapixel(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   /* Double check the permitted MNG features in case the app turned the feature
 | 
						|
    * on then off again.  Also make sure the color type is acceptable; it must
 | 
						|
    * be RGB or RGBA.
 | 
						|
    */
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
 | 
						|
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
 | 
						|
       (png_ptr->filter_method == PNG_INTRAPIXEL_DIFFERENCING) &&
 | 
						|
       (tc->format & (PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_COLORMAP)) ==
 | 
						|
         PNG_FORMAT_FLAG_COLOR)
 | 
						|
   {
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL) switch (PNG_TC_PIXEL_DEPTH(*tc))
 | 
						|
      {
 | 
						|
         case 24: (*tr)->fn = png_do_read_intrapixel_RGB8;   break;
 | 
						|
         case 32: (*tr)->fn = png_do_read_intrapixel_RGBA8;  break;
 | 
						|
         case 48: (*tr)->fn = png_do_read_intrapixel_RGB16;  break;
 | 
						|
         case 64: (*tr)->fn = png_do_read_intrapixel_RGBA16; break;
 | 
						|
         default: impossible("bit depth");
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   else
 | 
						|
      (*tr)->fn = NULL;
 | 
						|
}
 | 
						|
#endif /* MNG_READ_FEATURES_SUPPORTED */
 | 
						|
 | 
						|
#ifdef PNG_MNG_WRITE_FEATURES_SUPPORTED
 | 
						|
/* This is just the forward direction of the above:
 | 
						|
 *
 | 
						|
 *    red := red - green
 | 
						|
 *    blue:= blue- green
 | 
						|
 *
 | 
						|
 * Alpha is not changed.
 | 
						|
 */
 | 
						|
static void
 | 
						|
png_do_write_intrapixel_RGB8(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   /* TAKE CARE: dp and sp may be the same, in which case the assignments to *dp
 | 
						|
    * are overwriting sp[]
 | 
						|
    */
 | 
						|
   do
 | 
						|
   {
 | 
						|
      *dp++ = PNG_BYTE(sp[0] - sp[1]); /* red-green */
 | 
						|
      *dp++ = *++sp; /* green */
 | 
						|
      *dp++ = PNG_BYTE(sp[0] - sp[1]); /* green-blue */
 | 
						|
      sp += 2;
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_write_intrapixel_RGBA8(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   do
 | 
						|
   {
 | 
						|
      *dp++ = PNG_BYTE(sp[0] - sp[1]); /* red-green */
 | 
						|
      *dp++ = *++sp; /* green */
 | 
						|
      *dp++ = PNG_BYTE(sp[0] - sp[1]); /* green-blue */
 | 
						|
      sp += 2;
 | 
						|
      *dp++ = *sp++; /* alpha */
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_write_intrapixel_RGB16(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   do
 | 
						|
   {
 | 
						|
      unsigned int red   = png_get_uint_16(sp + 0);
 | 
						|
      unsigned int green = png_get_uint_16(sp + 2);
 | 
						|
      unsigned int blue  = png_get_uint_16(sp + 4);
 | 
						|
      sp += 6;
 | 
						|
 | 
						|
      red  -= green;
 | 
						|
      blue -= green;
 | 
						|
 | 
						|
      *dp++ = PNG_BYTE(red >> 8);
 | 
						|
      *dp++ = PNG_BYTE(red);
 | 
						|
      *dp++ = PNG_BYTE(green >> 8);
 | 
						|
      *dp++ = PNG_BYTE(green);
 | 
						|
      *dp++ = PNG_BYTE(blue >> 8);
 | 
						|
      *dp++ = PNG_BYTE(blue);
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_write_intrapixel_RGBA16(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_uint_32 width = tc->width;
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   /* As above but copy the alpha over too. */
 | 
						|
   do
 | 
						|
   {
 | 
						|
      unsigned int red   = png_get_uint_16(sp + 0);
 | 
						|
      unsigned int green = png_get_uint_16(sp + 2);
 | 
						|
      unsigned int blue  = png_get_uint_16(sp + 4);
 | 
						|
      sp += 6;
 | 
						|
 | 
						|
      red  -= green;
 | 
						|
      blue -= green;
 | 
						|
 | 
						|
      *dp++ = PNG_BYTE(red >> 8);
 | 
						|
      *dp++ = PNG_BYTE(red);
 | 
						|
      *dp++ = PNG_BYTE(green >> 8);
 | 
						|
      *dp++ = PNG_BYTE(green);
 | 
						|
      *dp++ = PNG_BYTE(blue >> 8);
 | 
						|
      *dp++ = PNG_BYTE(blue);
 | 
						|
      *dp++ = *sp++;
 | 
						|
      *dp++ = *sp++; /* alpha */
 | 
						|
   }
 | 
						|
   while (--width > 0);
 | 
						|
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   UNTESTED
 | 
						|
#  undef png_ptr
 | 
						|
   PNG_UNUSED(tr)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_init_write_intrapixel(png_transformp *tr, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   /* Write filter_method 64 (intrapixel differencing) only if:
 | 
						|
    *
 | 
						|
    * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED, and;
 | 
						|
    * 2. Libpng did not write a PNG signature (this filter_method is only
 | 
						|
    *    used in PNG datastreams that are embedded in MNG datastreams),
 | 
						|
    *    and;
 | 
						|
    * 3. The application called png_permit_mng_features with a mask that
 | 
						|
    *    included PNG_FLAG_MNG_FILTER_64, and;
 | 
						|
    * 4. The filter_method is 64, and;
 | 
						|
    * 5. The color_type is RGB or RGBA
 | 
						|
    */
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
 | 
						|
   if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
 | 
						|
       (png_ptr->filter_method == PNG_INTRAPIXEL_DIFFERENCING) &&
 | 
						|
       (tc->format & (PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_COLORMAP)) ==
 | 
						|
         PNG_FORMAT_FLAG_COLOR)
 | 
						|
   {
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL) switch (PNG_TC_PIXEL_DEPTH(*tc))
 | 
						|
      {
 | 
						|
         case 24: (*tr)->fn = png_do_write_intrapixel_RGB8;   break;
 | 
						|
         case 32: (*tr)->fn = png_do_write_intrapixel_RGBA8;  break;
 | 
						|
         case 48: (*tr)->fn = png_do_write_intrapixel_RGB16;  break;
 | 
						|
         case 64: (*tr)->fn = png_do_write_intrapixel_RGBA16; break;
 | 
						|
         default: impossible("bit depth");
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   else
 | 
						|
      (*tr)->fn = NULL;
 | 
						|
}
 | 
						|
#endif /* MNG_WRITE_FEATURES */
 | 
						|
 | 
						|
#ifdef PNG_MNG_FEATURES_SUPPORTED
 | 
						|
png_uint_32 PNGAPI
 | 
						|
png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifdef PNG_MNG_READ_FEATURES_SUPPORTED
 | 
						|
         if ((mng_features & PNG_FLAG_MNG_FILTER_64) != 0)
 | 
						|
            png_add_transform(png_ptr, 0/*size*/, png_init_read_intrapixel,
 | 
						|
               PNG_TR_MNG_INTRAPIXEL);
 | 
						|
#     else /* !MNG_READ_FEATURES */
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "MNG not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif /* !MNG_READ_FEATURES */
 | 
						|
 | 
						|
#     ifdef PNG_MNG_WRITE_FEATURES_SUPPORTED
 | 
						|
         if ((mng_features & PNG_FLAG_MNG_FILTER_64) != 0)
 | 
						|
            png_add_transform(png_ptr, 0/*size*/, png_init_write_intrapixel,
 | 
						|
               PNG_TR_MNG_INTRAPIXEL);
 | 
						|
#     else /* !MNG_WRITE_FEATURES */
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "MNG not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif /* !MNG_WRITE_FEATURES */
 | 
						|
 | 
						|
      return png_ptr->mng_features_permitted =
 | 
						|
         mng_features & PNG_ALL_MNG_FEATURES;
 | 
						|
   }
 | 
						|
 | 
						|
   return 0;
 | 
						|
}
 | 
						|
#endif /* MNG_FEATURES */
 | 
						|
 | 
						|
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_SWAP_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_FILLER_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_FILLER_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_STRIP_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_STRIP_16_TO_8_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_EXPAND_16_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
 | 
						|
/* This is a generic transform which manipulates the bytes in an input row.  The
 | 
						|
 * manipulations supported are:
 | 
						|
 *
 | 
						|
 *    Channel addition (alpha or filler)
 | 
						|
 *    Channel removal (alpha or filler)
 | 
						|
 *    Channel swaps - RGB to BGR, alpha/filler from last to first and vice versa
 | 
						|
 *
 | 
						|
 * The output is described in blocks of output pixel size 4-bit codes encoded
 | 
						|
 * as follows:
 | 
						|
 *
 | 
						|
 *    0        Advance the source pointer by the source pixel size, start the
 | 
						|
 *             code list again.  This code doesn't actually exist; it is simply
 | 
						|
 *             the result of emptying the code list.
 | 
						|
 *    1..3     An error (ignored; treated like 0)
 | 
						|
 *    4..7     Put filler[code-4] into the output
 | 
						|
 *    8..15    Put source byte[code-8] in the output
 | 
						|
 *
 | 
						|
 * The codes are held in a png_uint_32 parameter.  transform->args is used by
 | 
						|
 * the init routine to work out the required codes.  The format change is a mask
 | 
						|
 * which is XORed with the tc format.  Note that the init routine works out
 | 
						|
 * whether to work from the beginning or end of the row and the codes are always
 | 
						|
 * stored LSB first in the order needed.
 | 
						|
 */
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
   png_transform tr;
 | 
						|
   png_uint_32   codes;      /* As above */
 | 
						|
   unsigned int  format;     /* format after transform */
 | 
						|
   unsigned int  bit_depth;  /* bit depth after transform */
 | 
						|
   png_byte      filler[4];  /* Filler or alpha bytes, LSB first (see below) */
 | 
						|
}  png_transform_byte_op;
 | 
						|
 | 
						|
static void
 | 
						|
png_do_byte_ops_up(png_transformp *transform, png_transform_controlp tc)
 | 
						|
   /* Row width is unchanged or decreasing */
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_byte_op *tr =
 | 
						|
      png_transform_cast(png_transform_byte_op, *transform);
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   const unsigned int sp_advance = PNG_TC_PIXEL_DEPTH(*tc) >> 3;
 | 
						|
   const png_const_bytep ep = sp + PNG_TC_ROWBYTES(*tc);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
 | 
						|
   debug(tc->bit_depth == 8 || tc->bit_depth == 16);
 | 
						|
   debug((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0);
 | 
						|
 | 
						|
   tc->sp = tc->dp;
 | 
						|
   tc->format = tr->format;
 | 
						|
   tc->bit_depth = tr->bit_depth;
 | 
						|
 | 
						|
   /* 'output' is a 32-byte buffer that is used to delay writes for 16 bytes,
 | 
						|
    * avoiding overwrite when source and destination buffers are the same.
 | 
						|
    * 'hwm' is either 32 or 16, initially '32', when the byte counter 'i'
 | 
						|
    * reaches 'hwm' the last-but-one 16 bytes are written; the bytes
 | 
						|
    * [hwm..hwm+15] modulo 32.  hwm is then swapped to hwm+16 mod 32 and i
 | 
						|
    * continues to advance.  i is always below hwm.
 | 
						|
    *
 | 
						|
    * At the end the whole remaining buffer from hwm to i is written.
 | 
						|
    */
 | 
						|
   {
 | 
						|
      const png_uint_32 codes = tr->codes;
 | 
						|
      png_uint_32 code = codes;
 | 
						|
      unsigned int i, hwm; /* buffer index and high-water-mark */
 | 
						|
      png_byte output[32];
 | 
						|
 | 
						|
      hwm = 32;
 | 
						|
 | 
						|
      for (i=0;;)
 | 
						|
      {
 | 
						|
         unsigned int next_code = code & 0xf;
 | 
						|
 | 
						|
         if (next_code >= 8)
 | 
						|
            output[i++] = sp[next_code-8];
 | 
						|
 | 
						|
         else if (next_code >= 4)
 | 
						|
            output[i++] = tr->filler[next_code - 4];
 | 
						|
 | 
						|
         else /* end code */
 | 
						|
         {
 | 
						|
            sp += sp_advance;
 | 
						|
 | 
						|
            if (sp >= ep)
 | 
						|
               break; /* i may be == hwm at this point. */
 | 
						|
 | 
						|
            code = codes;
 | 
						|
            continue; /* no ouput produced, skip the check */
 | 
						|
         }
 | 
						|
 | 
						|
         code >>= 4; /* find the next code */
 | 
						|
 | 
						|
         if (i == hwm)
 | 
						|
         {
 | 
						|
            hwm &= 0x10U; /* 0 or 16 */
 | 
						|
            memcpy(dp, output + hwm, 16);
 | 
						|
            dp += 16;
 | 
						|
            i = hwm; /* reset i if hwm was 32 */
 | 
						|
            /* hwm is only ever 16 or 32: */
 | 
						|
            hwm += 16;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      /* Write from hwm to (i-1), the delay means there is always something to
 | 
						|
       * write.
 | 
						|
       */
 | 
						|
      hwm &= 0x10U;
 | 
						|
      if (hwm == 16)
 | 
						|
      {
 | 
						|
         debug(i <= 16);
 | 
						|
         memcpy(dp, output + hwm, 16);
 | 
						|
         dp += 16;
 | 
						|
      }
 | 
						|
 | 
						|
      if (i > 0)
 | 
						|
         memcpy(dp, output, i);
 | 
						|
 | 
						|
#     ifndef PNG_RELEASE_BUILD
 | 
						|
         dp += i;
 | 
						|
         /* The macro expansion exceeded the limit on ANSI strings, so split it:
 | 
						|
          */
 | 
						|
         dp -= PNG_TC_ROWBYTES(*tc);
 | 
						|
         debug(dp == tc->dp);
 | 
						|
#     endif
 | 
						|
   }
 | 
						|
 | 
						|
   debug(sp == ep);
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
static void
 | 
						|
png_do_byte_ops_down(png_transformp *transform, png_transform_controlp tc)
 | 
						|
   /* Row width is increasing */
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_byte_op *tr =
 | 
						|
      png_transform_cast(png_transform_byte_op, *transform);
 | 
						|
   const png_const_bytep ep = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   const unsigned int sp_advance = PNG_TC_PIXEL_DEPTH(*tc) >> 3;
 | 
						|
   png_const_bytep sp = ep + PNG_TC_ROWBYTES(*tc);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_alloc_size_t dest_rowbytes;
 | 
						|
 | 
						|
   debug(tc->bit_depth == 8U || tc->bit_depth == 16U);
 | 
						|
   debug((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U);
 | 
						|
 | 
						|
   tc->sp = tc->dp;
 | 
						|
   tc->format = tr->format;
 | 
						|
   tc->bit_depth = tr->bit_depth;
 | 
						|
   dest_rowbytes = PNG_TC_ROWBYTES(*tc);
 | 
						|
   dp += dest_rowbytes;
 | 
						|
 | 
						|
   /* In this case the 32-byte buffer is written downwards with a writes delayed
 | 
						|
    * by 16 bytes as before.  'hwm' is lower than i; 0 or 16.
 | 
						|
    */
 | 
						|
   {
 | 
						|
      const png_uint_32 codes = tr->codes;
 | 
						|
      png_uint_32 code = codes;
 | 
						|
      unsigned int size, hwm, i;
 | 
						|
      png_byte output[32] = { 0 };
 | 
						|
 | 
						|
      /* This catches an empty codes array, which would cause all the input to
 | 
						|
       * be skipped and, potentially, a garbage output[] to be written (once) to
 | 
						|
       * *dp.
 | 
						|
       */
 | 
						|
      affirm((codes & 0xFU) >= 4U);
 | 
						|
 | 
						|
      /* Align the writes to a 16-byte multiple from the start of the
 | 
						|
       * destination buffer:
 | 
						|
       */
 | 
						|
      size = dest_rowbytes & 0xFU;
 | 
						|
      if (size == 0U) size = 16U;
 | 
						|
      i = size+16U;
 | 
						|
      sp -= sp_advance; /* Move 1 pixel back */
 | 
						|
      hwm = 0U;
 | 
						|
 | 
						|
      for (;;)
 | 
						|
      {
 | 
						|
         unsigned int next_code = code & 0xFU;
 | 
						|
 | 
						|
         if (next_code >= 8U)
 | 
						|
            output[--i] = sp[next_code-8U];
 | 
						|
 | 
						|
         else if (next_code >= 4U)
 | 
						|
            output[--i] = tr->filler[next_code - 4U];
 | 
						|
 | 
						|
         else /* end code */
 | 
						|
         {
 | 
						|
            sp -= sp_advance;
 | 
						|
 | 
						|
            if (sp < ep)
 | 
						|
               break;
 | 
						|
 | 
						|
            code = codes;
 | 
						|
            continue; /* no ouput produced, skip the check */
 | 
						|
         }
 | 
						|
 | 
						|
         code >>= 4; /* find the next code */
 | 
						|
 | 
						|
         if (i == hwm)
 | 
						|
         {
 | 
						|
            /* A partial copy comes at the beginning to align the copies to a
 | 
						|
             * 16-byte boundary.  The bytes to be written are the bytes
 | 
						|
             * i+16..(hwm-1) except that the partial buffer may reduce this.
 | 
						|
             */
 | 
						|
            dp -= size;
 | 
						|
            hwm ^= 0x10U; /* == i+16 mod 32 */
 | 
						|
            memcpy(dp, output + hwm, size);
 | 
						|
            size = 16U;
 | 
						|
            if (i == 0U) i = 32U;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      /* The loop above only exits with an exit code, so 'i' has been checked
 | 
						|
       * against 'hwm' before and, because of the alignment, i will always be
 | 
						|
       * either 16 or 32:
 | 
						|
       */
 | 
						|
      debug((i == 16U || i == 32U) & (((i & 0x10U)^0x10U) == hwm));
 | 
						|
      debug(sp+sp_advance == ep);
 | 
						|
 | 
						|
      /* At the end the bytes i..(hwm-1) need to be written, with the proviso
 | 
						|
       * that 'size' will be less than 16 for short rows.  If 'size' is still a
 | 
						|
       * short value then the range to be written is output[i..16+(size-1)],
 | 
						|
       * otherwise (size == 16) either this is the first write and a full 32
 | 
						|
       * bytes will be written (hwm == 0, i == 32) or 16 bytes need to be
 | 
						|
       * written.
 | 
						|
       */
 | 
						|
      if (size < 16U)
 | 
						|
      {
 | 
						|
         debug(i == 16U);
 | 
						|
         dp -= size;
 | 
						|
         memcpy(dp, output + i, size);
 | 
						|
      }
 | 
						|
 | 
						|
      else /* size == 16 */
 | 
						|
      {
 | 
						|
         debug(size == 16U);
 | 
						|
 | 
						|
         /* Write i..(hwm-1); 16 or 32 bytes, however if 32 bytes are written
 | 
						|
          * they are contiguous and i==0.
 | 
						|
          *
 | 
						|
          * hwm is 0 or 16, i is 16 or 32, swap 0 and 32:
 | 
						|
          */
 | 
						|
         if (hwm == 0U) hwm = 32U;
 | 
						|
         if (i == 32U) i = 0U;
 | 
						|
         affirm(i < hwm);
 | 
						|
         debug(hwm == i+16U || (i == 0U && hwm == 32U));
 | 
						|
 | 
						|
         hwm -= i;
 | 
						|
         dp -= hwm;
 | 
						|
         memcpy(dp, output+i, hwm);
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   debug(dp == png_upcast(png_bytep, tc->dp));
 | 
						|
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
#endif /* READ_TRANSFORMS */
 | 
						|
 | 
						|
/* 16 bit byte swapping */
 | 
						|
static void
 | 
						|
png_do_bswap(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_byte_op *tr =
 | 
						|
      png_transform_cast(png_transform_byte_op, *transform);
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   const png_alloc_size_t rowbytes = PNG_TC_ROWBYTES(*tc);
 | 
						|
 | 
						|
   tc->format = tr->format;
 | 
						|
   tc->bit_depth = tr->bit_depth;
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
#  ifdef _XOPEN_SOURCE
 | 
						|
      /* byte swapping often has incredibly fast implementations because of the
 | 
						|
       * importance in handling ethernet traffic.  X/Open defines swab() for
 | 
						|
       * this purpose and it is widely supported and normally incredibly fast:
 | 
						|
       */
 | 
						|
      debug((rowbytes & 1) == 0);
 | 
						|
      swab(sp, dp, rowbytes);
 | 
						|
#  else /* !_XOPEN_SOURCE */
 | 
						|
      {
 | 
						|
         const png_const_bytep ep = sp + rowbytes - 1;
 | 
						|
 | 
						|
         while (sp < ep)
 | 
						|
         {
 | 
						|
            png_byte b0 = *sp++;
 | 
						|
            *dp++ = *sp++;
 | 
						|
            *dp++ = b0;
 | 
						|
         }
 | 
						|
 | 
						|
         debug(sp == ep+1); /* even number of bytes */
 | 
						|
      }
 | 
						|
#  endif
 | 
						|
 | 
						|
   PNG_UNUSED(transform)
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
 | 
						|
/* The following flags, store in tr->args, are set by the relevant PNGAPI
 | 
						|
 * png_set calls then resolved below.
 | 
						|
 */
 | 
						|
#define PNG_BO_STRIP_ALPHA  0x0001U /* Remove an alpha channel (read only) */
 | 
						|
#define PNG_BO_CHOP_16_TO_8 0x0002U /* Chop 16-bit to 8-bit channels */
 | 
						|
#define PNG_BO_GRAY_TO_RGB  0x0004U /* G <-> RGB; replicate channels */
 | 
						|
/* QUANTIZE happens here */
 | 
						|
#define PNG_BO_EXPAND_16    0x0008U /* Expand 8-bit channels to 16-bit */
 | 
						|
#define PNG_BO_BGR          0x0010U /* RGB <-> BGR */
 | 
						|
#define PNG_BO_FILLER       0x0020U /* Add a filler/alpha */
 | 
						|
#define PNG_BO_SWAP_ALPHA   0x0040U /* xA <-> Ax; alpha swap */
 | 
						|
#define PNG_BO_SWAP_16      0x0080U /* 16-bit channel byte swapping */
 | 
						|
 | 
						|
/* The following are additional flags to qualify the transforms: */
 | 
						|
#define PNG_BO_FILLER_ALPHA 0x4000U /* The filler is an alpha value */
 | 
						|
#define PNG_BO_FILLER_FIRST 0x8000U /* The filler comes first */
 | 
						|
 | 
						|
static void
 | 
						|
png_init_byte_ops(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   /* In the absence of png_set_quantize none of the above operations apply to a
 | 
						|
    * palette row except indirectly; they may apply if the palette was expanded,
 | 
						|
    * but this happens earlier in the pipeline.
 | 
						|
    *
 | 
						|
    * In the presence of png_set_quantize the rules are considerably more
 | 
						|
    * complex.  In libpng 1.6.0 the following operations occur before
 | 
						|
    * png_do_quantize:
 | 
						|
    *
 | 
						|
    *    PNG_BO_GRAY_TO_RGB (png_do_gray_to_rgb, but only sometimes)
 | 
						|
    *    PNG_BO_STRIP_ALPHA (png_do_strip_channel; removes alpha)
 | 
						|
    *    encode_alpha
 | 
						|
    *    scale_16_to_8
 | 
						|
    *    PNG_BO_CHOP_16_TO_8 (png_do_chop)
 | 
						|
    *
 | 
						|
    * The following occur afterward:
 | 
						|
    *
 | 
						|
    *    PNG_BO_EXPAND_16 (png_do_expand_16)
 | 
						|
    *    PNG_BO_GRAY_TO_RGB (png_do_gray_to_rgb, normally)
 | 
						|
    *    PNG_BO_BGR (png_do_bgr)
 | 
						|
    *    PNG_BO_FILLER (png_do_read_filler)
 | 
						|
    *    PNG_BO_SWAP_ALPHA (png_do_read_swap_alpha)
 | 
						|
    *    PNG_BO_SWAP_16 (png_do_swap; 16-bit byte swap)
 | 
						|
    *
 | 
						|
    * The gray to RGB operation needs to occur early for GA or gray+tRNS images
 | 
						|
    * where the pixels are being composed on a non-gray value.  For the moment
 | 
						|
    * we assume that if this is necessary the following 'init' code will see RGB
 | 
						|
    * at this point.
 | 
						|
    *
 | 
						|
    * The quantize operation operates only if:
 | 
						|
    *
 | 
						|
    *    1) tc->bit_depth is 8
 | 
						|
    *    2) The color type exactly matches that required by the parameters to
 | 
						|
    *       png_set_quantize; it can be RGB, RGBA or palette, but
 | 
						|
    *       png_set_quantize (not the init routine) determines this.
 | 
						|
    *
 | 
						|
    * To avoid needing to know this here the two stage initialization is used
 | 
						|
    * with two transforms, one pre-quantization the other post.  In the first
 | 
						|
    * stage the correct row format and depth is set up.  In the second stage the
 | 
						|
    * pre-quantization transform looks for a post-quantization transform
 | 
						|
    * immediately following and, if it exists, transfers its flags to that.
 | 
						|
    */
 | 
						|
   png_structp png_ptr = tc->png_ptr;
 | 
						|
   png_transform_byte_op *tr =
 | 
						|
      png_transform_cast(png_transform_byte_op, *transform);
 | 
						|
   png_uint_32 args = tr->tr.args;
 | 
						|
   const unsigned int png_format = tc->format;
 | 
						|
   unsigned int format = png_format; /* memory format */
 | 
						|
   const unsigned int png_bit_depth = tc->bit_depth;
 | 
						|
   unsigned int bit_depth = png_bit_depth; /* memory bit depth */
 | 
						|
 | 
						|
   debug(tc->init);
 | 
						|
 | 
						|
   /* Channel swaps do not occur on COLORMAP format data at present because the
 | 
						|
    * COLORMAP is limited to 1 byte per pixel (so there is nothing to
 | 
						|
    * manipulate). Likewise for low bit depth gray, however the code below may
 | 
						|
    * widen 8-bit gray to RGB.
 | 
						|
    */
 | 
						|
   if ((png_format & PNG_FORMAT_FLAG_COLORMAP) != 0U || png_bit_depth < 8U)
 | 
						|
   {
 | 
						|
      tr->tr.fn = NULL;
 | 
						|
      return;
 | 
						|
   }
 | 
						|
 | 
						|
   /* This will normally happen in TC_INIT_FORMAT, but if there is a
 | 
						|
    * png_do_quantize operation which doesn't apply (this is unlikely) it will
 | 
						|
    * happen in TC_INIT_FINAL.
 | 
						|
    */
 | 
						|
   if (tr->tr.next != NULL && tr->tr.next->order == PNG_TR_CHANNEL_POSTQ)
 | 
						|
   {
 | 
						|
      debug(tr->tr.order == PNG_TR_CHANNEL_PREQ);
 | 
						|
 | 
						|
      /* So we can merge this transform into the next one, note that because the
 | 
						|
       * PNG_BO_FILLER operation is POSTQ we don't need to copy anything other
 | 
						|
       * than the flags.
 | 
						|
       */
 | 
						|
      debug((args & tr->tr.next->args) == 0U);
 | 
						|
      tr->tr.next->args |= args;
 | 
						|
      tr->tr.fn = NULL;
 | 
						|
      return;
 | 
						|
   }
 | 
						|
 | 
						|
   /* Else compact the flags for this transform - this is done in both
 | 
						|
    * TC_INIT_FORMAT and TC_INIT_FINAL because it is safer that way; the copy
 | 
						|
    * above shouldn't actually affect the results but might result in TO8 and
 | 
						|
    * TO16 cancelling each other because they are in separate transforms before
 | 
						|
    * the merge above.
 | 
						|
    *
 | 
						|
    * QUIET API CHANGE:
 | 
						|
    * For compatiblity with earlier versions of libpng these tests need to
 | 
						|
    * occur in the same order as the earlier transforms; 'TO8' combined with
 | 
						|
    * 'TO16' did actually do something to 16-bit data, however now it just
 | 
						|
    * preserves the original bit depth.
 | 
						|
    */
 | 
						|
   if ((args & PNG_BO_STRIP_ALPHA) != 0U)
 | 
						|
   {
 | 
						|
      if ((format & PNG_FORMAT_FLAG_ALPHA) != 0U)
 | 
						|
         format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_ALPHA);
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_STRIP_ALPHA);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_CHOP_16_TO_8) != 0U)
 | 
						|
   {
 | 
						|
      /* This is the quiet API CHANGE; in fact it isn't necessary, but it
 | 
						|
       * seems likely that requesting both operations is a mistake:
 | 
						|
       */
 | 
						|
      if ((args & PNG_BO_EXPAND_16) != 0U)
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_CHOP_16_TO_8|PNG_BO_EXPAND_16);
 | 
						|
 | 
						|
      else if (bit_depth == 16U)
 | 
						|
      {
 | 
						|
         bit_depth = 8U;
 | 
						|
 | 
						|
         /* This also makes the tRNS chunk unusable: */
 | 
						|
         tc->invalid_info |= PNG_INFO_tRNS+PNG_INFO_hIST+PNG_INFO_pCAL;
 | 
						|
         /* These need further processing: PNG_INFO_sBIT, PNG_INFO_bKGD */
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_CHOP_16_TO_8);
 | 
						|
   }
 | 
						|
 | 
						|
   /* QUANTIZE happens here */
 | 
						|
 | 
						|
   if ((args & PNG_BO_EXPAND_16) != 0U)
 | 
						|
   {
 | 
						|
      /* This only does the 8 to 16-bit part of the expansion by multiply by
 | 
						|
       * 65535/255 (257) using byte replication.  The cases of low bit depth
 | 
						|
       * gray being expanded to 16-bit have to be handled separately.
 | 
						|
       */
 | 
						|
      if (bit_depth == 8U)
 | 
						|
         bit_depth = 16U;
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_EXPAND_16);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_GRAY_TO_RGB) != 0U)
 | 
						|
   {
 | 
						|
      if ((format & PNG_FORMAT_FLAG_COLOR) == 0U)
 | 
						|
         format |= PNG_FORMAT_FLAG_COLOR;
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_GRAY_TO_RGB);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_BGR) != 0U)
 | 
						|
   {
 | 
						|
      /* This does not happen on colormaps: */
 | 
						|
      if ((format & PNG_FORMAT_FLAG_COLOR) != 0U && !tc->palette)
 | 
						|
         format |= PNG_FORMAT_FLAG_BGR;
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_BGR);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_FILLER) != 0U)
 | 
						|
   {
 | 
						|
      if ((format & PNG_FORMAT_FLAG_ALPHA) == 0U)
 | 
						|
      {
 | 
						|
         format |= PNG_FORMAT_FLAG_ALPHA;
 | 
						|
         tc->channel_add = 1U;
 | 
						|
         /* And SWAP_ALPHA did not occur, because prior to 1.7.0 the filler op
 | 
						|
          * did not set ALPHA in the color type, so use SWAP_ALPHA to handle the
 | 
						|
          * before/after filler location.
 | 
						|
          *
 | 
						|
          * NOTE: this occurs twice, once in TC_START and once in TC_FINAL, but
 | 
						|
          * that is ok, the operations are idempotent.
 | 
						|
          *
 | 
						|
          * For colormaps (tc->palette set) the filler will just end up setting
 | 
						|
          * all the tRNS entries and PNG_BO_SWAP_ALPHA will be cancelled below.
 | 
						|
          */
 | 
						|
         if ((args & PNG_BO_FILLER_FIRST) != 0U)
 | 
						|
            args |= PNG_BO_SWAP_ALPHA;
 | 
						|
 | 
						|
         else
 | 
						|
            args &= PNG_BIC_MASK(PNG_BO_SWAP_ALPHA);
 | 
						|
 | 
						|
         if (!(args & PNG_BO_FILLER_ALPHA)) /* filler is not alpha */
 | 
						|
            format |= PNG_FORMAT_FLAG_AFILLER;
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_FILLER);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_SWAP_ALPHA) != 0U)
 | 
						|
   {
 | 
						|
      /* This does not happen on color maps: */
 | 
						|
      if ((format & PNG_FORMAT_FLAG_ALPHA) != 0U && !tc->palette)
 | 
						|
         format |= PNG_FORMAT_FLAG_AFIRST;
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_SWAP_ALPHA);
 | 
						|
   }
 | 
						|
 | 
						|
   if ((args & PNG_BO_SWAP_16) != 0U)
 | 
						|
   {
 | 
						|
      if (bit_depth == 16U)
 | 
						|
         format |= PNG_FORMAT_FLAG_SWAPPED;
 | 
						|
 | 
						|
      else
 | 
						|
         args &= PNG_BIC_MASK(PNG_BO_SWAP_16);
 | 
						|
   }
 | 
						|
 | 
						|
   if (args != 0U)
 | 
						|
   {
 | 
						|
      /* At the end (TC_INIT_FINAL) work out the mapping array using the codes
 | 
						|
       * defined above and store the format and bit depth changes (as changes,
 | 
						|
       * so they will work either forward or backward).  The filler array must
 | 
						|
       * be set up by the png_set API.
 | 
						|
       */
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL)
 | 
						|
      {
 | 
						|
         const unsigned int png_pixel_size = PNG_TC_PIXEL_DEPTH(*tc) >> 3;
 | 
						|
 | 
						|
         tc->format = format;
 | 
						|
         tc->bit_depth = bit_depth;
 | 
						|
 | 
						|
         {
 | 
						|
            const unsigned int memory_pixel_size = PNG_TC_PIXEL_DEPTH(*tc) >> 3;
 | 
						|
            unsigned int code_size, src_size;
 | 
						|
            int go_down;
 | 
						|
            png_byte codes[8];
 | 
						|
 | 
						|
            /* The codes array maps the PNG format into the memory format
 | 
						|
             * assuming the mapping works upwards in the address space.
 | 
						|
             * Initially ignore the bit depth and just work on the first four
 | 
						|
             * bytes.
 | 
						|
             */
 | 
						|
            codes[0] = 8U;
 | 
						|
            codes[1] = 9U;
 | 
						|
            codes[2] = 10U;
 | 
						|
            codes[3] = 11U;
 | 
						|
            codes[7] = codes[6] = codes[5] = codes[4] = 0U/*error*/;
 | 
						|
 | 
						|
            /* PNG_BO_STRIP_ALPHA: handled by memory_pixel_size */
 | 
						|
            /* PNG_BO_CHOP_16_TO_8: handled below */
 | 
						|
            /* PNG_BO_EXPAND_16: handled below */
 | 
						|
 | 
						|
            if ((args & PNG_BO_GRAY_TO_RGB) != 0U)
 | 
						|
            {
 | 
						|
               codes[3] = 9U; /* alpha, if present */
 | 
						|
               codes[2] = codes[1] = 8U;
 | 
						|
 | 
						|
#              ifdef PNG_READ_tRNS_SUPPORTED
 | 
						|
                  /* Gray to RGB, so copy the tRNS G value into r,g,b: */
 | 
						|
                  if (png_ptr->num_trans == 1U)
 | 
						|
                     png_ptr->trans_color.blue =
 | 
						|
                        png_ptr->trans_color.green =
 | 
						|
                        png_ptr->trans_color.red =
 | 
						|
                        png_ptr->trans_color.gray;
 | 
						|
#              endif /* READ_tRNS */
 | 
						|
            }
 | 
						|
 | 
						|
            /* 'BGR' and gray-to-RGB are mutually exclusive; with gray-to-RGB
 | 
						|
             * codes[0] == codes[2] == 8
 | 
						|
             */
 | 
						|
            else if ((args & PNG_BO_BGR) != 0U)
 | 
						|
            {
 | 
						|
               codes[0] = 10U;
 | 
						|
               codes[2] = 8U;
 | 
						|
            }
 | 
						|
 | 
						|
            if ((args & PNG_BO_FILLER) != 0U)
 | 
						|
            {
 | 
						|
               /* The filler alway goes after; for a 'before' filler the code
 | 
						|
                * above turns on SWAP_ALPHA too.  The gray-to-RGB transform has
 | 
						|
                * happened already, so the location of the filler channel is
 | 
						|
                * given by 'format':
 | 
						|
                */
 | 
						|
               if ((format & PNG_FORMAT_FLAG_COLOR) != 0U)
 | 
						|
                  codes[3] = 4U; /* low byte of filler */
 | 
						|
 | 
						|
               else
 | 
						|
                  codes[1] = 4U;
 | 
						|
            }
 | 
						|
 | 
						|
            if ((args & PNG_BO_SWAP_ALPHA) != 0U)
 | 
						|
            {
 | 
						|
               if ((format & PNG_FORMAT_FLAG_COLOR) != 0U)
 | 
						|
               {
 | 
						|
                  /* BGR may have swapped the early codes. gray-to-RGB may have
 | 
						|
                   * set them all to '8':
 | 
						|
                   */
 | 
						|
                  png_byte acode = codes[3];
 | 
						|
                  codes[3] = codes[2];
 | 
						|
                  codes[2] = codes[1];
 | 
						|
                  codes[1] = codes[0];
 | 
						|
                  codes[0] = acode;
 | 
						|
               }
 | 
						|
 | 
						|
               else /* GA format */
 | 
						|
                  codes[0] = codes[1], codes[1] = 8U;
 | 
						|
            }
 | 
						|
 | 
						|
            /* PNG_BO_SWAP_16: 16-bit only, handled below */
 | 
						|
 | 
						|
            /* Now the 16-bit dependent stuff. */
 | 
						|
            if ((args & PNG_BO_CHOP_16_TO_8) != 0U)
 | 
						|
            {
 | 
						|
               /* 16-bit input, 8-bit output, happens before FILLER so the
 | 
						|
                * filler must be an 8-bit value.  Apart from a filler code (4 in
 | 
						|
                * this case) the code must be adjusted from byte 'x' to byte
 | 
						|
                * '2x' to select the MSB of each 16-bit channel.
 | 
						|
                *
 | 
						|
                * We must use PNG_FORMAT_CHANNELS here because the memory pixel
 | 
						|
                * size might (in the future) include a TO16 operation.
 | 
						|
                */
 | 
						|
               unsigned int i = PNG_FORMAT_CHANNELS(format);
 | 
						|
 | 
						|
               while (i > 0U)
 | 
						|
               {
 | 
						|
                  unsigned int code = codes[--i];
 | 
						|
 | 
						|
                  if (code > 8U) /* 8, 4 need not change */
 | 
						|
                     codes[i] = PNG_BYTE(8U+2U*(code-8U));
 | 
						|
               }
 | 
						|
            }
 | 
						|
 | 
						|
            if ((args & PNG_BO_EXPAND_16) != 0U)
 | 
						|
            {
 | 
						|
               /* Don't expect this with CHOP, but it will work, setting the low
 | 
						|
                * 8-bits of each 16-bit value to the high bits.
 | 
						|
                */
 | 
						|
               unsigned int i = PNG_FORMAT_CHANNELS(format);
 | 
						|
 | 
						|
               while (i > 0U)
 | 
						|
               {
 | 
						|
                  png_byte code = codes[--i];
 | 
						|
 | 
						|
                  /* BSWAP is after FILLER, however the data passed in is a
 | 
						|
                   * machine native png_uint_16.  We don't know until this init
 | 
						|
                   * routine whether the data is an 8 or 16-bit value because we
 | 
						|
                   * don't know the full set of transforms the app will apply
 | 
						|
                   * when the png_set_filler API is called.
 | 
						|
                   *
 | 
						|
                   * This means that the data in tr->filler[] needs to have the
 | 
						|
                   * low bits in a known place, so the code here puts the low 8
 | 
						|
                   * bits in filler[0], code 4.  Hence the following:
 | 
						|
                   */
 | 
						|
                  if (code == 4U)
 | 
						|
                     codes[2U*i/*MSB*/] = 5U, codes[2U*i+1U/*LSB*/] = 4U;
 | 
						|
 | 
						|
                  else
 | 
						|
                     codes[2U*i] = codes[2U*i+1U] = code;
 | 
						|
               }
 | 
						|
 | 
						|
#              ifdef PNG_READ_tRNS_SUPPORTED
 | 
						|
                  /* We're just duplicating bytes, so the tRNS chunk can be
 | 
						|
                   * maintained if present.  If the tRNS is for a colormap this
 | 
						|
                   * produces garbage in trans_color, but it isn't used.
 | 
						|
                   */
 | 
						|
                  if (png_ptr->num_trans == 1U)
 | 
						|
                  {
 | 
						|
#                    define TO16(x) x = PNG_UINT_16((x & 0xFFU) * 0x101U)
 | 
						|
                     TO16(png_ptr->trans_color.gray);
 | 
						|
                     TO16(png_ptr->trans_color.red);
 | 
						|
                     TO16(png_ptr->trans_color.green);
 | 
						|
                     TO16(png_ptr->trans_color.blue);
 | 
						|
#                    undef TO16
 | 
						|
                  }
 | 
						|
#              endif /* READ_tRNS */
 | 
						|
            }
 | 
						|
 | 
						|
            else if (bit_depth == 16U)
 | 
						|
            {
 | 
						|
               /* 16-bit input and output. */
 | 
						|
               unsigned int i = PNG_FORMAT_CHANNELS(format);
 | 
						|
 | 
						|
               while (i > 0U)
 | 
						|
               {
 | 
						|
                  unsigned int code = codes[--i];
 | 
						|
 | 
						|
                  if (code == 4U) /* as above */
 | 
						|
                     codes[2U*i/*MSB*/] = 5U, codes[2U*i+1U/*LSB*/] = 4U;
 | 
						|
 | 
						|
                  else
 | 
						|
                  {
 | 
						|
                     codes[2U*i] = PNG_BYTE(8U+2U*(code-8U));
 | 
						|
                     codes[2U*i+1U] = PNG_BYTE(8U+2U*(code-8U)+1U);
 | 
						|
                  }
 | 
						|
               }
 | 
						|
            }
 | 
						|
 | 
						|
            if ((args & PNG_BO_SWAP_16) != 0U)
 | 
						|
            {
 | 
						|
               /* bswap the memory bytes. */
 | 
						|
               unsigned int i;
 | 
						|
               png_byte bswap_codes[sizeof codes];
 | 
						|
 | 
						|
               debug((memory_pixel_size & 1U) == 0U);
 | 
						|
 | 
						|
               for (i=0U; i<sizeof codes; ++i)
 | 
						|
                  bswap_codes[i] = codes[i ^ 1U];
 | 
						|
 | 
						|
               memcpy(codes, bswap_codes, sizeof codes);
 | 
						|
            }
 | 
						|
 | 
						|
#           ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
 | 
						|
               /* Handle the 'write' case; the codes[] array must be inverted,
 | 
						|
                * it lists the PNG pixel for each memory pixel, we need it to
 | 
						|
                * list the memory pixel for each PNG pixel.
 | 
						|
                */
 | 
						|
               if (!png_ptr->read_struct)
 | 
						|
               {
 | 
						|
                  /* There are no write transforms that add data to the PNG
 | 
						|
                   * file; the 'filler' transform removes a channel, but that is
 | 
						|
                   * the limit of the changes.
 | 
						|
                   */
 | 
						|
                  unsigned int i = 0U;
 | 
						|
                  png_byte write_codes[8U];
 | 
						|
 | 
						|
                  memset(write_codes, 0, sizeof write_codes);
 | 
						|
 | 
						|
                  while (i<memory_pixel_size)
 | 
						|
                  {
 | 
						|
                     unsigned int code = codes[i];
 | 
						|
 | 
						|
                     if (code >= 8U) /* 8+index of PNG byte */
 | 
						|
                        write_codes[code-8U] = PNG_BYTE(8U+i);
 | 
						|
                     /* else this is a filler byte to be removed */
 | 
						|
                     else
 | 
						|
                        debug(code == 4U || code == 5U);
 | 
						|
 | 
						|
                     ++i;
 | 
						|
                  }
 | 
						|
 | 
						|
                  code_size = png_pixel_size;
 | 
						|
                  src_size = memory_pixel_size;
 | 
						|
                  tr->format = png_format;
 | 
						|
                  tr->bit_depth = png_bit_depth;
 | 
						|
 | 
						|
                  /* The PNG size should always be <= to the memory size, the
 | 
						|
                   * source pointer will be the memory, the destination the PNG
 | 
						|
                   * format, so it should always be possible to do the upwards
 | 
						|
                   * copy.
 | 
						|
                   */
 | 
						|
                  go_down = png_pixel_size > memory_pixel_size;
 | 
						|
                  affirm(!go_down);
 | 
						|
                  memcpy(codes, write_codes, sizeof codes);
 | 
						|
               }
 | 
						|
 | 
						|
               else
 | 
						|
#           endif /* WRITE_TRANSFORMS */
 | 
						|
            {
 | 
						|
               code_size = memory_pixel_size;
 | 
						|
               src_size = png_pixel_size;
 | 
						|
               tr->format = format;
 | 
						|
               tr->bit_depth = bit_depth;
 | 
						|
               go_down = png_pixel_size < memory_pixel_size;
 | 
						|
            }
 | 
						|
 | 
						|
            /* Record this for debugging: */
 | 
						|
            tr->tr.args = args;
 | 
						|
 | 
						|
            /* For the same-pixel-size case check for a bswap; this is available
 | 
						|
             * in heavily optimized forms and is a common operation (50% of the
 | 
						|
             * time) with 16-bit PNG data, particularly given the handling in
 | 
						|
             * the simplified API.
 | 
						|
             */
 | 
						|
            if (!go_down)
 | 
						|
            {
 | 
						|
               if (memory_pixel_size == png_pixel_size)
 | 
						|
               {
 | 
						|
                  int the_same = 1;
 | 
						|
                  int swapped = (memory_pixel_size & 1) == 0; /* even count */
 | 
						|
                  unsigned int i;
 | 
						|
 | 
						|
                  for (i=0U; i<memory_pixel_size; ++i)
 | 
						|
                  {
 | 
						|
                     if (codes[i] != 8U+i)
 | 
						|
                     {
 | 
						|
                        the_same = 0;
 | 
						|
                        if (codes[i] != 8U+(i^1U))
 | 
						|
                           swapped = 0;
 | 
						|
                        if (!swapped)
 | 
						|
                           break;
 | 
						|
                     }
 | 
						|
 | 
						|
                     else /* byte is copied, so it can't be swapped! */
 | 
						|
                     {
 | 
						|
                        swapped = 0;
 | 
						|
                        if (!the_same)
 | 
						|
                           break;
 | 
						|
                     }
 | 
						|
                  }
 | 
						|
 | 
						|
                  /* Use the 'bswap' routine if possible. */
 | 
						|
                  if (swapped)
 | 
						|
                  {
 | 
						|
                     tr->tr.fn = png_do_bswap;
 | 
						|
                     return;
 | 
						|
                  }
 | 
						|
 | 
						|
                  else if (the_same)
 | 
						|
                     impossible("not reached");
 | 
						|
               }
 | 
						|
 | 
						|
               tr->tr.fn = png_do_byte_ops_up;
 | 
						|
 | 
						|
               /* Construct the code, forwards: */
 | 
						|
               {
 | 
						|
                  unsigned int i = code_size;
 | 
						|
                  png_uint_32 code = 0U;
 | 
						|
 | 
						|
                  while (i > 0U)
 | 
						|
                  {
 | 
						|
                     unsigned int next = codes[--i];
 | 
						|
 | 
						|
                     code <<= 4U;
 | 
						|
 | 
						|
                     if ((next >= 8U && next < 8U+src_size) ||
 | 
						|
                           next == 4U || next == 5U)
 | 
						|
                        code += next;
 | 
						|
 | 
						|
                     else
 | 
						|
                        impossible("invalid code (up)");
 | 
						|
                  }
 | 
						|
 | 
						|
                  tr->codes = code;
 | 
						|
               }
 | 
						|
            }
 | 
						|
 | 
						|
            else /* go_down */
 | 
						|
#           ifdef PNG_READ_TRANSFORMS_SUPPORTED
 | 
						|
               {
 | 
						|
                  tr->tr.fn = png_do_byte_ops_down;
 | 
						|
 | 
						|
                  /* Construct the code, backwards: */
 | 
						|
                  {
 | 
						|
                     unsigned int i = 0U;
 | 
						|
                     png_uint_32 code = 0U;
 | 
						|
 | 
						|
                     while (i < code_size)
 | 
						|
                     {
 | 
						|
                        unsigned int next = codes[i++];
 | 
						|
 | 
						|
                        code <<= 4;
 | 
						|
 | 
						|
                        if ((next >= 8U && next < 8U+src_size) ||
 | 
						|
                              next == 4U || next == 5U)
 | 
						|
                           code += next;
 | 
						|
 | 
						|
                        else
 | 
						|
                           impossible("invalid code (down)");
 | 
						|
                     }
 | 
						|
 | 
						|
                     tr->codes = code;
 | 
						|
                  }
 | 
						|
               }
 | 
						|
#           else /* !READ_TRANSFORMS */
 | 
						|
               impossible("not reached"); /* because of the affirm above */
 | 
						|
#           endif /* !READ_TRANSFORMS */
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      else /* TC_INIT_FORMAT: just store modified 'args' */
 | 
						|
      {
 | 
						|
         tc->format = format;
 | 
						|
         tc->bit_depth = bit_depth;
 | 
						|
         tr->tr.args = args;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   else /* the transform is not applicable */
 | 
						|
      tr->tr.fn = NULL;
 | 
						|
}
 | 
						|
#endif /* SWAP poo */
 | 
						|
 | 
						|
#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
 | 
						|
static void
 | 
						|
png_init_rgb_to_gray_byte_ops(png_transformp *transform,
 | 
						|
   png_transform_controlp tc)
 | 
						|
{
 | 
						|
   /* This just delay initializes the function; all the transform initialization
 | 
						|
    * has been done below.
 | 
						|
    */
 | 
						|
   (*transform)->fn = png_do_byte_ops_up;
 | 
						|
 | 
						|
   /*  If this happens on a row do the transform immediately: */
 | 
						|
   if (!tc->init)
 | 
						|
      png_do_byte_ops_up(transform, tc);
 | 
						|
 | 
						|
   else
 | 
						|
   {
 | 
						|
      /* This doing the init - update the row information here */
 | 
						|
#     define png_ptr (tc->png_ptr)
 | 
						|
      png_transform_byte_op *tr =
 | 
						|
         png_transform_cast(png_transform_byte_op, *transform);
 | 
						|
 | 
						|
      debug(tc->bit_depth == 8U || tc->bit_depth == 16U);
 | 
						|
      debug((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0U &&
 | 
						|
            (tc->format & PNG_FORMAT_FLAG_COLOR) != 0U);
 | 
						|
 | 
						|
      tc->format = tr->format;
 | 
						|
      tc->bit_depth = tr->bit_depth;
 | 
						|
#     undef png_ptr
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void /* PRIVATE */
 | 
						|
png_add_rgb_to_gray_byte_ops(png_structrp png_ptr, png_transform_controlp tc,
 | 
						|
   unsigned int index, unsigned int order)
 | 
						|
   /* Add a byte_ops transform to convert RGB or RGBA data to 'gray' by
 | 
						|
    * selecting just the given change [index]  The transform added is added at
 | 
						|
    * 'order'.
 | 
						|
    */
 | 
						|
{
 | 
						|
   png_transform_byte_op *tr = png_transform_cast(png_transform_byte_op,
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_rgb_to_gray_byte_ops, order));
 | 
						|
 | 
						|
   affirm((tc->format & (PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_COLORMAP)) ==
 | 
						|
            PNG_FORMAT_FLAG_COLOR &&
 | 
						|
          index <= 2 && tc->init == PNG_TC_INIT_FINAL);
 | 
						|
 | 
						|
   tr->format = tc->format & PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR);
 | 
						|
   tr->bit_depth = tc->bit_depth;
 | 
						|
 | 
						|
   /* For 1 byte channel [index] plus, maybe, alpha: */
 | 
						|
   if (tc->bit_depth == 8)
 | 
						|
      tr->codes = 8U + index +
 | 
						|
         ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 ? (8U+3U) << 4 : 0U);
 | 
						|
 | 
						|
   else
 | 
						|
   {
 | 
						|
      affirm(tc->bit_depth == 16);
 | 
						|
 | 
						|
      /* As above, but two bytes; [2*index] and [2*index+1] */
 | 
						|
      index *= 2U;
 | 
						|
      tr->codes = (8U + index) + ((9U + index) << 4) +
 | 
						|
         ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0 ?
 | 
						|
            ((8U+6U) + ((9U+6U) << 4)) << 8 : 0U);
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* READ_RGB_TO_GRAY */
 | 
						|
 | 
						|
#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) &&\
 | 
						|
    defined(PNG_READ_BACKGROUND_SUPPORTED)
 | 
						|
void /* PRIVATE */
 | 
						|
png_push_gray_to_rgb_byte_ops(png_transformp *transform,
 | 
						|
   png_transform_controlp tc)
 | 
						|
   /* This is an init-time utility to add appropriate byte ops to expand a
 | 
						|
    * grayscale PNG data set to RGB.
 | 
						|
    */
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transformp tr = png_push_transform(png_ptr,
 | 
						|
      sizeof (png_transform_byte_op), png_init_byte_ops, transform, NULL);
 | 
						|
 | 
						|
   tr->args = PNG_BO_GRAY_TO_RGB;
 | 
						|
   debug(tr == *transform);
 | 
						|
   png_init_byte_ops(transform, tc);
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
#endif /* GRAY_TO_RGB && READ_BACKGROUND */
 | 
						|
 | 
						|
#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 | 
						|
void /* PRIVATE */
 | 
						|
png_add_strip_alpha_byte_ops(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   png_add_transform(png_ptr, sizeof (png_transform_byte_op), png_init_byte_ops,
 | 
						|
      PNG_TR_CHANNEL_PREQ)->args |= PNG_BO_STRIP_ALPHA;
 | 
						|
}
 | 
						|
#endif /* READ_STRIP_ALPHA */
 | 
						|
 | 
						|
#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
 | 
						|
/* Chop 16-bit depth files to 8-bit depth */
 | 
						|
void PNGAPI
 | 
						|
png_set_strip_16(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_PREQ)->args |=
 | 
						|
         PNG_BO_CHOP_16_TO_8;
 | 
						|
}
 | 
						|
#endif /* READ_STRIP_16_TO_8 */
 | 
						|
 | 
						|
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 | 
						|
void PNGAPI
 | 
						|
png_set_gray_to_rgb(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      png_set_expand_gray_1_2_4_to_8(png_ptr);
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_PREQ)->args |=
 | 
						|
         PNG_BO_GRAY_TO_RGB;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* READ_GRAY_TO_RGB */
 | 
						|
 | 
						|
/* QUANTIZE */
 | 
						|
 | 
						|
#ifdef PNG_READ_EXPAND_16_SUPPORTED
 | 
						|
/* Expand to 16-bit channels.  PNG_BO_EXPAND_16 also expands the tRNS chunk if
 | 
						|
 * it is present, but it requires low bit depth grayscale expanded first.  This
 | 
						|
 * must also force palette to RGB.
 | 
						|
 */
 | 
						|
void PNGAPI
 | 
						|
png_set_expand_16(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      png_set_expand_gray_1_2_4_to_8(png_ptr);
 | 
						|
      png_set_palette_to_rgb(png_ptr);
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_POSTQ)->args |=
 | 
						|
         PNG_BO_EXPAND_16;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* READ_EXPAND_16 */
 | 
						|
 | 
						|
#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
 | 
						|
void PNGAPI
 | 
						|
png_set_bgr(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifndef PNG_READ_BGR_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_bgr not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_BGR_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_bgr not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_POSTQ)->args |=
 | 
						|
         PNG_BO_BGR;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* BGR */
 | 
						|
 | 
						|
#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
 | 
						|
/* This includes png_set_filler and png_set_add_alpha.  The only difference
 | 
						|
 * between the two is that the latter resulted in PNG_COLOR_MASK_ALPHA being
 | 
						|
 * added to the info_ptr color type, if png_read_update_info was called whereas
 | 
						|
 * the former did not.
 | 
						|
 *
 | 
						|
 * Regardless of whether the added channel resulted in the change to the
 | 
						|
 * png_info color type, the SWAP_ALPHA transform was not performed, even though
 | 
						|
 * it apparently occured after the add, because PNG_COLOR_MASK_ALPHA was never
 | 
						|
 * set in the 1.6 'row_info'.
 | 
						|
 *
 | 
						|
 * Consequently 'SWAP_ALPHA' and 'FILLER' were independent; one or the other
 | 
						|
 * would occur depending on the color type (not the number of channels) prior to
 | 
						|
 * the two transforms.
 | 
						|
 *
 | 
						|
 * Prior to 1.7.0 the app could obtain information about the memory format by
 | 
						|
 * calling png_read_update_info followed by png_get_color_type and
 | 
						|
 * png_get_channels.  The first would return PNG_COLOR_TYPE..._ALPHA if
 | 
						|
 * png_set_add_alpha was performed and the base type if png_set_filler was
 | 
						|
 * performed, however in both cases png_get_channels would return the extra
 | 
						|
 * channel; 2 or 4.
 | 
						|
 *
 | 
						|
 * The app could also insert a user transform callback and view the color type
 | 
						|
 * in the old "row_info" structure, however this resulted in an inconsistent
 | 
						|
 * color type because png_set_alpha did not add COLOR_MASK_ALPHA to the color
 | 
						|
 * type.
 | 
						|
 *
 | 
						|
 * Hence API CHANGE: 1.7.0, row transform callbacks now see the same color type
 | 
						|
 * as reported by png_get_color_type after png_read_update_info.
 | 
						|
 */
 | 
						|
/* Add a filler byte on read, or remove a filler or alpha byte on write.
 | 
						|
 * The filler type has changed in v0.95 to allow future 2-byte fillers
 | 
						|
 * for 48-bit input data, as well as to avoid problems with some compilers
 | 
						|
 * that don't like bytes as parameters.
 | 
						|
 */
 | 
						|
static void
 | 
						|
set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc, int alpha)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      if (filler_loc != PNG_FILLER_BEFORE && filler_loc != PNG_FILLER_AFTER)
 | 
						|
      {
 | 
						|
         png_app_error(png_ptr, "png_set_filler: invalid filler location");
 | 
						|
         return;
 | 
						|
      }
 | 
						|
 | 
						|
#     ifndef PNG_READ_SWAP_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_filler not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_SWAP_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_filler not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      {
 | 
						|
         png_transform_byte_op *tr =
 | 
						|
            png_transform_cast(png_transform_byte_op,
 | 
						|
               png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
                  png_init_byte_ops, PNG_TR_CHANNEL_POSTQ));
 | 
						|
         png_uint_32 args = PNG_BO_FILLER;
 | 
						|
 | 
						|
         if (filler_loc == PNG_FILLER_BEFORE)
 | 
						|
            args |= PNG_BO_FILLER_FIRST;
 | 
						|
 | 
						|
         if (alpha)
 | 
						|
            args |= PNG_BO_FILLER_ALPHA;
 | 
						|
 | 
						|
         tr->tr.args |= args;
 | 
						|
 | 
						|
         /* The filler must be stored LSByte first: */
 | 
						|
         tr->filler[0] = PNG_BYTE(filler >>  0);
 | 
						|
         tr->filler[1] = PNG_BYTE(filler >>  8);
 | 
						|
         tr->filler[2] = PNG_BYTE(filler >> 16);
 | 
						|
         tr->filler[3] = PNG_BYTE(filler >> 24);
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
void PNGAPI
 | 
						|
png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc)
 | 
						|
{
 | 
						|
   set_filler(png_ptr, filler, filler_loc, 0/*!alpha*/);
 | 
						|
}
 | 
						|
 | 
						|
/* Added to libpng-1.2.7 */
 | 
						|
void PNGAPI
 | 
						|
png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc)
 | 
						|
{
 | 
						|
   set_filler(png_ptr, filler, filler_loc, 1/*alpha*/);
 | 
						|
}
 | 
						|
#endif /* FILLER */
 | 
						|
 | 
						|
#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
 | 
						|
    defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
 | 
						|
void PNGAPI
 | 
						|
png_set_swap_alpha(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifndef PNG_READ_SWAP_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_swap_alpha not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_SWAP_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_swap_alpha not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_POSTQ)->args |=
 | 
						|
         PNG_BO_SWAP_ALPHA;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* SWAP_ALPHA */
 | 
						|
 | 
						|
#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
 | 
						|
void PNGAPI
 | 
						|
png_set_swap(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifndef PNG_READ_SWAP_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_swap not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_SWAP_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_swap not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_byte_op),
 | 
						|
         png_init_byte_ops, PNG_TR_CHANNEL_POSTQ)->args |=
 | 
						|
         PNG_BO_SWAP_16;
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* SWAP */
 | 
						|
 | 
						|
#if defined(PNG_READ_PACKSWAP_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_PACKSWAP_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_INVERT_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
 | 
						|
static png_alloc_size_t
 | 
						|
row_align(png_transform_controlp tc)
 | 
						|
   /* Utiltity to align the source row (sp) in a transform control; it does this
 | 
						|
    * by simply copying it to dp if it is not already aligned.  As a convenience
 | 
						|
    * the utility returns the number of bytes in the row.
 | 
						|
    */
 | 
						|
{
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
   png_const_voidp sp = tc->sp;
 | 
						|
   png_voidp dp = tc->dp;
 | 
						|
   png_alloc_size_t rowbytes = PNG_TC_ROWBYTES(*tc);
 | 
						|
 | 
						|
   /* For alignment; if png_alignof is not supported by the compiler this will
 | 
						|
    * always do an initial memcpy if the source and destination are not the
 | 
						|
    * same.  We can only get here for write; the read case always uses locally
 | 
						|
    * allocated buffers, only write reads from the application data directly.
 | 
						|
    */
 | 
						|
#  ifdef png_alignof
 | 
						|
      debug(png_isaligned(dp, png_uint_32));
 | 
						|
#  endif
 | 
						|
   if (sp != dp && !png_ptr->read_struct && !png_isaligned(sp, png_uint_32))
 | 
						|
   {
 | 
						|
      UNTESTED
 | 
						|
      memcpy(dp, sp, rowbytes);
 | 
						|
      tc->sp = dp;
 | 
						|
   }
 | 
						|
 | 
						|
   return rowbytes;
 | 
						|
}
 | 
						|
#endif /* Stuff that needs row_align */
 | 
						|
 | 
						|
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
 | 
						|
/* Bit-ops; invert bytes.  This works for mono inverts too because even the low
 | 
						|
 * bit depths can be handled as bytes (since there can be no intervening
 | 
						|
 * channels).
 | 
						|
 */
 | 
						|
#define PNG_B_INVERT_MONO  1U
 | 
						|
#define PNG_B_INVERT_RGB   2U /* not set, used below */
 | 
						|
#define PNG_B_INVERT_ALPHA 4U
 | 
						|
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
   png_transform tr;
 | 
						|
   unsigned int  step0; /* initial advance on sp and dp */
 | 
						|
   unsigned int  step;  /* advance after start */
 | 
						|
   png_uint_32   mask;  /* XOR mask */
 | 
						|
}  png_transform_bit_op;
 | 
						|
 | 
						|
static void
 | 
						|
png_do_invert_all(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   const png_const_structp png_ptr = tc->png_ptr;
 | 
						|
   /* Invert the whole row, quickly */
 | 
						|
   const png_const_voidp dp_end = png_upcast(png_bytep, tc->dp) + row_align(tc);
 | 
						|
   png_uint_32p dp = png_voidcast(png_uint_32p, tc->dp);
 | 
						|
   png_const_uint_32p sp = png_voidcast(png_const_uint_32p, tc->sp);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   if (png_ptr->read_struct)
 | 
						|
   {
 | 
						|
      tc->format |= PNG_FORMAT_FLAG_RANGE;
 | 
						|
      tc->range++;
 | 
						|
   }
 | 
						|
 | 
						|
   else if (--(tc->range) == 0)
 | 
						|
      tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_RANGE);
 | 
						|
 | 
						|
   while (png_upcast(void*,dp) < dp_end)
 | 
						|
      *dp++ = ~*sp++;
 | 
						|
 | 
						|
   PNG_UNUSED(transform);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_invert_channel(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   const png_const_structp png_ptr = tc->png_ptr;
 | 
						|
   /* Invert just one channel in the row. */
 | 
						|
   const png_transform_bit_op * const tr =
 | 
						|
      png_transform_cast(png_transform_bit_op, *transform);
 | 
						|
   const png_uint_32 mask = tr->mask;
 | 
						|
   const unsigned int step = tr->step;
 | 
						|
   const unsigned int step0 = tr->step0;
 | 
						|
   const png_const_voidp dp_end = png_upcast(png_bytep, tc->dp) + row_align(tc);
 | 
						|
   png_uint_32p dp = png_voidcast(png_uint_32p, tc->dp);
 | 
						|
   png_const_uint_32p sp = png_voidcast(png_const_uint_32p, tc->sp);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   if (png_ptr->read_struct)
 | 
						|
   {
 | 
						|
      tc->format |= PNG_FORMAT_FLAG_RANGE;
 | 
						|
      tc->range++;
 | 
						|
   }
 | 
						|
 | 
						|
   else if (--(tc->range) == 0)
 | 
						|
      tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_RANGE);
 | 
						|
 | 
						|
   if (sp == dp || step == 1)
 | 
						|
   {
 | 
						|
      sp += step0;
 | 
						|
      dp += step0;
 | 
						|
 | 
						|
      while (png_upcast(void*,dp) < dp_end)
 | 
						|
         *dp = *sp ^ mask, dp += step, sp += step;
 | 
						|
   }
 | 
						|
 | 
						|
   else /* step == 2, copy required */
 | 
						|
   {
 | 
						|
      if (step0) /* must be 1 */
 | 
						|
         *dp++ = *sp++;
 | 
						|
 | 
						|
      while (png_upcast(void*,dp) < dp_end)
 | 
						|
      {
 | 
						|
         *dp++ = *sp++ ^ mask;
 | 
						|
         if (!(png_upcast(void*,dp) < dp_end))
 | 
						|
            break;
 | 
						|
         *dp++ = *sp++;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   PNG_UNUSED(transform);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_init_invert(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_bit_op *tr =
 | 
						|
      png_transform_cast(png_transform_bit_op, *transform);
 | 
						|
   png_uint_32 invert = tr->tr.args;
 | 
						|
   png_uint_32 present; /* channels present */
 | 
						|
 | 
						|
   if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
 | 
						|
      present = 0;
 | 
						|
 | 
						|
   else /* not color mapped */
 | 
						|
   {
 | 
						|
      if ((tc->format & PNG_FORMAT_FLAG_COLOR) != 0)
 | 
						|
         present = PNG_B_INVERT_RGB;
 | 
						|
      else
 | 
						|
         present = PNG_B_INVERT_MONO;
 | 
						|
 | 
						|
      if ((tc->format & PNG_FORMAT_FLAG_ALPHA) != 0)
 | 
						|
         present |= PNG_B_INVERT_ALPHA;
 | 
						|
   }
 | 
						|
 | 
						|
   /* Cannot invert things that aren't there: */
 | 
						|
   invert &= present;
 | 
						|
 | 
						|
   /* If nothing can be inverted is present the transform is not applicable: */
 | 
						|
   if (invert == 0)
 | 
						|
      (*transform)->fn = NULL;
 | 
						|
 | 
						|
   else
 | 
						|
   {
 | 
						|
      tc->format |= PNG_FORMAT_FLAG_RANGE;
 | 
						|
      tc->range++;
 | 
						|
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL)
 | 
						|
      {
 | 
						|
         /* If everything that is present is to be inverted just invert the
 | 
						|
          * whole row:
 | 
						|
          */
 | 
						|
         if (invert == present)
 | 
						|
            (*transform)->fn = png_do_invert_all;
 | 
						|
 | 
						|
         else
 | 
						|
         {
 | 
						|
            /* One thing is to be inverted, G or A: */
 | 
						|
            unsigned int channels = PNG_TC_CHANNELS(*tc);
 | 
						|
            unsigned int channel =
 | 
						|
               (tc->format & PNG_FORMAT_FLAG_AFIRST) != 0 ? 0 : channels-1;
 | 
						|
 | 
						|
            affirm(channels == 2 || channels == 4);
 | 
						|
 | 
						|
            if (invert != PNG_B_INVERT_ALPHA)
 | 
						|
            {
 | 
						|
               debug(invert == PNG_B_INVERT_MONO && channels == 2 &&
 | 
						|
                     present == PNG_B_INVERT_MONO+PNG_B_INVERT_ALPHA);
 | 
						|
               channel = (channels-1) - channel;
 | 
						|
            }
 | 
						|
 | 
						|
            affirm(tc->bit_depth == 8 || tc->bit_depth == 16);
 | 
						|
 | 
						|
            /* So channels[channel] is to be inverted, make a mask: */
 | 
						|
            {
 | 
						|
               union
 | 
						|
               {
 | 
						|
                  png_byte bytes[8];
 | 
						|
                  png_uint_32 words[2];
 | 
						|
               } masks;
 | 
						|
 | 
						|
               memset(&masks, 0, sizeof masks);
 | 
						|
 | 
						|
               if (tc->bit_depth == 8)
 | 
						|
               {
 | 
						|
                  /* channels is 2 or 4, channel < 4. */
 | 
						|
                  masks.bytes[channel+channels] = masks.bytes[channel] = 0xff;
 | 
						|
                  tr->step = 1;
 | 
						|
                  tr->mask = masks.words[0];
 | 
						|
                  tr->step0 = 0;
 | 
						|
               }
 | 
						|
 | 
						|
               else /* tc->bit_depth == 16 */
 | 
						|
               {
 | 
						|
                  channel <<= 1; /* in bytes */
 | 
						|
                  masks.bytes[channel+1] = masks.bytes[channel] = 0xff;
 | 
						|
 | 
						|
                  if (channels == 2)
 | 
						|
                  {
 | 
						|
                     tr->step = 1;
 | 
						|
                     tr->mask = masks.words[0];
 | 
						|
                     tr->step0 = 0;
 | 
						|
                  }
 | 
						|
 | 
						|
                  else /* channels == 4 */
 | 
						|
                  {
 | 
						|
                     tr->step = 2;
 | 
						|
 | 
						|
                     if (masks.words[0] == 0)
 | 
						|
                     {
 | 
						|
                        tr->mask = masks.words[1];
 | 
						|
                        tr->step0 = 1;
 | 
						|
                     }
 | 
						|
 | 
						|
                     else
 | 
						|
                     {
 | 
						|
                        tr->mask = masks.words[0];
 | 
						|
                        tr->step0 = 0;
 | 
						|
                     }
 | 
						|
                  }
 | 
						|
               }
 | 
						|
            }
 | 
						|
 | 
						|
            (*transform)->fn = png_do_invert_channel;
 | 
						|
         }
 | 
						|
      }
 | 
						|
   }
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
 | 
						|
#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
 | 
						|
void PNGAPI
 | 
						|
png_set_invert_alpha(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_bit_op),
 | 
						|
         png_init_invert, PNG_TR_INVERT)->args |= PNG_B_INVERT_ALPHA;
 | 
						|
#     ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
 | 
						|
         /* This is necessary to avoid palette processing on write; the only
 | 
						|
          * transform that applies to colormapped images is the tRNS chunk
 | 
						|
          * invert.
 | 
						|
          */
 | 
						|
         png_ptr->write_invert_alpha = 1U;
 | 
						|
#     endif
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* INVERT_ALPHA */
 | 
						|
 | 
						|
#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
 | 
						|
void PNGAPI
 | 
						|
png_set_invert_mono(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
      png_add_transform(png_ptr, sizeof (png_transform_bit_op),
 | 
						|
         png_init_invert, PNG_TR_INVERT)->args |= PNG_B_INVERT_MONO;
 | 
						|
}
 | 
						|
#endif /* INVERT */
 | 
						|
#endif /* INVERT_ALPHA || INVERT */
 | 
						|
 | 
						|
/*
 | 
						|
 *   WARNING
 | 
						|
 *     WARNING
 | 
						|
 *       WARNING
 | 
						|
 *         WARNING
 | 
						|
 *           WARNING  The transforms below are temporary; they can and will be
 | 
						|
 *         WARNING    heavily optimized before release.
 | 
						|
 *       WARNING
 | 
						|
 *     WARNING
 | 
						|
 *   WARNING
 | 
						|
 */
 | 
						|
#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
   png_transform  tr;
 | 
						|
   png_color_8    true_bits;
 | 
						|
}  png_transform_shift;
 | 
						|
 | 
						|
/* Shift pixel values to take advantage of whole range.  Pass the
 | 
						|
 * true number of bits in bit_depth.  The row should be packed
 | 
						|
 * according to tc->bit_depth.  Thus, if you had a row of
 | 
						|
 * bit depth 4, but the pixels only had values from 0 to 7, you
 | 
						|
 * would pass 3 as bit_depth, and this routine would translate the
 | 
						|
 * data to 0 to 15.
 | 
						|
 *
 | 
						|
 * NOTE: this is horrible complexity for no value.  Once people suggested they
 | 
						|
 * were selling 16-bit displays with 5:6:5 bits spread R:G:B but so far as I
 | 
						|
 * could determine these displays produced intermediate grey (uncolored) colors,
 | 
						|
 * which is impossible with a true 5:6:5, so most likely 5:6:5 was marketing.
 | 
						|
 */
 | 
						|
static unsigned int
 | 
						|
set_shifts(unsigned int format, unsigned int bit_depth,
 | 
						|
   png_const_color_8p true_bits, int *shift_start, int *shift_dec)
 | 
						|
{
 | 
						|
   unsigned int channels = 0;
 | 
						|
 | 
						|
   if ((format & (PNG_FORMAT_FLAG_ALPHA+PNG_FORMAT_FLAG_AFIRST)) ==
 | 
						|
       (PNG_FORMAT_FLAG_ALPHA+PNG_FORMAT_FLAG_AFIRST))
 | 
						|
      ++channels; /* filled in below */
 | 
						|
 | 
						|
   if ((format & PNG_FORMAT_FLAG_COLOR) != 0)
 | 
						|
   {
 | 
						|
      unsigned int offset = /* 0 or 2 as appropriate for red */
 | 
						|
         ((format & PNG_FORMAT_FLAG_BGR) != 0) << 1;
 | 
						|
 | 
						|
      shift_start[channels+offset] = bit_depth - true_bits->red;
 | 
						|
      if (shift_dec != NULL) shift_dec[channels+offset] = true_bits->red;
 | 
						|
 | 
						|
      shift_start[channels+1] = bit_depth - true_bits->green;
 | 
						|
      if (shift_dec != NULL) shift_dec[channels+1] = true_bits->green;
 | 
						|
 | 
						|
      offset ^= 2; /* for blue */
 | 
						|
      shift_start[channels+offset] = bit_depth - true_bits->blue;
 | 
						|
      if (shift_dec != NULL) shift_dec[channels+offset] = true_bits->blue;
 | 
						|
 | 
						|
      channels += 3;
 | 
						|
   }
 | 
						|
 | 
						|
   else /* no color: gray */
 | 
						|
   {
 | 
						|
      shift_start[channels] = bit_depth - true_bits->gray;
 | 
						|
      if (shift_dec != NULL) shift_dec[channels] = true_bits->gray;
 | 
						|
      ++channels;
 | 
						|
   }
 | 
						|
 | 
						|
   if ((format & PNG_FORMAT_FLAG_ALPHA) != 0)
 | 
						|
   {
 | 
						|
      const unsigned int offset =
 | 
						|
         (format & PNG_FORMAT_FLAG_AFIRST) != 0 ? 0 : channels++;
 | 
						|
 | 
						|
      shift_start[offset] = bit_depth - true_bits->alpha;
 | 
						|
      if (shift_dec != NULL) shift_dec[offset] = true_bits->alpha;
 | 
						|
   }
 | 
						|
 | 
						|
   return channels;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef PNG_WRITE_SHIFT_SUPPORTED
 | 
						|
static void
 | 
						|
png_do_shift(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_shift *tr =
 | 
						|
      png_transform_cast(png_transform_shift, *transform);
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_const_bytep dp_end = dp + PNG_TC_ROWBYTES(*tc);
 | 
						|
 | 
						|
   png_debug(1, "in png_do_shift");
 | 
						|
 | 
						|
   if (--(tc->range) == 0)
 | 
						|
      tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_RANGE);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
 | 
						|
   {
 | 
						|
      int shift_start[4], shift_dec[4];
 | 
						|
      unsigned int channels = set_shifts(tc->format, tc->bit_depth,
 | 
						|
         &tr->true_bits, shift_start, shift_dec);
 | 
						|
 | 
						|
      debug(PNG_TC_CHANNELS(*tc) == channels);
 | 
						|
 | 
						|
      /* With low res depths, could only be grayscale, so one channel */
 | 
						|
      if (tc->bit_depth < 8)
 | 
						|
      {
 | 
						|
         unsigned int mask;
 | 
						|
 | 
						|
         UNTESTED
 | 
						|
         affirm(channels == 1);
 | 
						|
         /* This doesn't matter but we expect to run before packswap: */
 | 
						|
         debug(!(tc->format & PNG_FORMAT_FLAG_SWAPPED));
 | 
						|
 | 
						|
         if (tr->true_bits.gray == 1 && tc->bit_depth == 2)
 | 
						|
            mask = 0x55;
 | 
						|
 | 
						|
         else if (tc->bit_depth == 4 && tr->true_bits.gray == 3)
 | 
						|
            mask = 0x11;
 | 
						|
 | 
						|
         else
 | 
						|
            mask = 0xff;
 | 
						|
 | 
						|
         while (dp < dp_end)
 | 
						|
         {
 | 
						|
            int j;
 | 
						|
            unsigned int v, out;
 | 
						|
 | 
						|
            v = *sp++;
 | 
						|
            out = 0;
 | 
						|
 | 
						|
            for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
 | 
						|
            {
 | 
						|
               if (j > 0)
 | 
						|
                  out |= v << j;
 | 
						|
 | 
						|
               else
 | 
						|
                  out |= (v >> (-j)) & mask;
 | 
						|
            }
 | 
						|
 | 
						|
            *dp++ = png_check_byte(png_ptr, out);
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      else if (tc->bit_depth == 8)
 | 
						|
      {
 | 
						|
         unsigned int c = 0;
 | 
						|
 | 
						|
         UNTESTED
 | 
						|
         while (dp < dp_end)
 | 
						|
         {
 | 
						|
 | 
						|
            int j;
 | 
						|
            unsigned int v, out;
 | 
						|
 | 
						|
            v = *sp++;
 | 
						|
            out = 0;
 | 
						|
 | 
						|
            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
 | 
						|
            {
 | 
						|
               if (j > 0)
 | 
						|
                  out |= v << j;
 | 
						|
 | 
						|
               else
 | 
						|
                  out |= v >> (-j);
 | 
						|
            }
 | 
						|
 | 
						|
            *dp++ = png_check_byte(png_ptr, out);
 | 
						|
            if (++c == channels) c = 0;
 | 
						|
         }
 | 
						|
      }
 | 
						|
 | 
						|
      else /* tc->bit_depth == 16 */
 | 
						|
      {
 | 
						|
         unsigned int c = 0, s0, s1;
 | 
						|
 | 
						|
         UNTESTED
 | 
						|
         if ((tc->format & PNG_FORMAT_FLAG_SWAPPED) != 0)
 | 
						|
            s0 = 0, s1 = 8; /* LSB */
 | 
						|
 | 
						|
         else
 | 
						|
            s0 = 8, s1 = 0; /* MSB */
 | 
						|
 | 
						|
         while (dp < dp_end)
 | 
						|
         {
 | 
						|
            int j;
 | 
						|
            unsigned int value, v;
 | 
						|
 | 
						|
            v = *sp++ << s0;
 | 
						|
            v += *sp++ << s1;
 | 
						|
            value = 0;
 | 
						|
 | 
						|
            for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
 | 
						|
            {
 | 
						|
               if (j > 0)
 | 
						|
                  value |= v << j;
 | 
						|
 | 
						|
               else
 | 
						|
                  value |= v >> (-j);
 | 
						|
            }
 | 
						|
 | 
						|
            *dp++ = PNG_BYTE(value >> s0);
 | 
						|
            *dp++ = PNG_BYTE(value >> s1);
 | 
						|
         }
 | 
						|
      }
 | 
						|
   }
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
#endif /* WRITE_SHIFT */
 | 
						|
 | 
						|
#ifdef PNG_READ_SHIFT_SUPPORTED
 | 
						|
/* Reverse the effects of png_do_shift.  This routine merely shifts the
 | 
						|
 * pixels back to their significant bits values.  Thus, if you have
 | 
						|
 * a row of bit depth 8, but only 5 are significant, this will shift
 | 
						|
 * the values back to 0 through 31.
 | 
						|
 */
 | 
						|
static void
 | 
						|
png_do_unshift(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_transform_shift *tr =
 | 
						|
      png_transform_cast(png_transform_shift, *transform);
 | 
						|
   png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
 | 
						|
   png_bytep dp = png_voidcast(png_bytep, tc->dp);
 | 
						|
   png_const_bytep dp_end = dp + PNG_TC_ROWBYTES(*tc);
 | 
						|
 | 
						|
   png_debug(1, "in png_do_unshift");
 | 
						|
 | 
						|
   tc->range++;
 | 
						|
   tc->format |= PNG_FORMAT_FLAG_RANGE;
 | 
						|
 | 
						|
   {
 | 
						|
      int shift[4];
 | 
						|
      unsigned int channels = set_shifts(tc->format, tc->bit_depth,
 | 
						|
         &tr->true_bits, shift, NULL);
 | 
						|
 | 
						|
      debug(PNG_TC_CHANNELS(*tc) == channels);
 | 
						|
 | 
						|
      {
 | 
						|
         unsigned int c, have_shift;
 | 
						|
 | 
						|
         for (c = have_shift = 0; c < channels; ++c)
 | 
						|
         {
 | 
						|
            /* A shift of more than the bit depth is an error condition but it
 | 
						|
             * gets ignored here.
 | 
						|
             */
 | 
						|
            if (shift[c] <= 0 || (unsigned)/*SAFE*/shift[c] >= tc->bit_depth)
 | 
						|
               shift[c] = 0;
 | 
						|
 | 
						|
            else
 | 
						|
               have_shift = 1;
 | 
						|
         }
 | 
						|
 | 
						|
         if (have_shift == 0)
 | 
						|
            return;
 | 
						|
      }
 | 
						|
 | 
						|
      /* The code below will copy sp to dp, so: */
 | 
						|
      tc->sp = dp;
 | 
						|
 | 
						|
      switch (tc->bit_depth)
 | 
						|
      {
 | 
						|
         default:
 | 
						|
            /* Must be 1bpp gray: should not be here! */
 | 
						|
            impossible("unshift bit depth");
 | 
						|
            /* NOTREACHED */
 | 
						|
            break;
 | 
						|
 | 
						|
         case 2:
 | 
						|
            /* Must be 2bpp gray */
 | 
						|
            debug(channels == 1 && shift[0] == 1);
 | 
						|
            debug(!(tc->format & PNG_FORMAT_FLAG_SWAPPED));
 | 
						|
 | 
						|
            while (dp < dp_end)
 | 
						|
               *dp++ = (*sp++ >> 1) & 0x55;
 | 
						|
            break;
 | 
						|
 | 
						|
         case 4:
 | 
						|
            /* Must be 4bpp gray */
 | 
						|
            debug(channels == 1);
 | 
						|
            debug(!(tc->format & PNG_FORMAT_FLAG_SWAPPED));
 | 
						|
            {
 | 
						|
               unsigned int gray_shift = shift[0];
 | 
						|
               unsigned int mask =  0xf >> gray_shift; /* <= 4 bits */
 | 
						|
 | 
						|
               mask |= mask << 4; /* <= 8 bits */
 | 
						|
 | 
						|
               while (dp < dp_end)
 | 
						|
                  *dp++ = (png_byte)/*SAFE*/((*sp++ >> gray_shift) & mask);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
         case 8:
 | 
						|
            /* Single byte components, G, GA, RGB, RGBA */
 | 
						|
            {
 | 
						|
               unsigned int channel = 0;
 | 
						|
 | 
						|
               while (dp < dp_end)
 | 
						|
               {
 | 
						|
                  *dp++ = (png_byte)/*SAFE*/(*sp++ >> shift[channel]);
 | 
						|
                  if (++channel >= channels)
 | 
						|
                     channel = 0;
 | 
						|
               }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
 | 
						|
         case 16:
 | 
						|
            /* Double byte components, G, GA, RGB, RGBA */
 | 
						|
            {
 | 
						|
               unsigned int channel = 0;
 | 
						|
               unsigned int s0, s1;
 | 
						|
 | 
						|
               if ((tc->format & PNG_FORMAT_FLAG_SWAPPED) != 0)
 | 
						|
                  s0 = 0, s1 = 8; /* LSB */
 | 
						|
 | 
						|
               else
 | 
						|
                  s0 = 8, s1 = 0; /* MSB */
 | 
						|
 | 
						|
               while (dp < dp_end)
 | 
						|
               {
 | 
						|
                  unsigned int value = *sp++ << s0;
 | 
						|
 | 
						|
                  value += *sp++ << s1; /* <= 16 bits */
 | 
						|
 | 
						|
                  value >>= shift[channel];
 | 
						|
                  if (++channel >= channels) channel = 0;
 | 
						|
                  *dp++ = PNG_BYTE(value >> s0);
 | 
						|
                  *dp++ = PNG_BYTE(value >> s1);
 | 
						|
               }
 | 
						|
            }
 | 
						|
            break;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
#endif /* READ_SHIFT */
 | 
						|
 | 
						|
static void
 | 
						|
init_shift(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_const_structp png_ptr = tc->png_ptr;
 | 
						|
 | 
						|
   /* These shifts apply to the component value, not the pixel index, so skip
 | 
						|
    * palette data.  In addition there is no *write* shift for palette entries;
 | 
						|
    * only a read one, so skip the write/palette case too.
 | 
						|
    */
 | 
						|
   if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0 &&
 | 
						|
       (png_ptr->read_struct || !tc->palette))
 | 
						|
   {
 | 
						|
      /* The only change to the format is to mark the data as having a non-PNG
 | 
						|
       * range.
 | 
						|
       */
 | 
						|
      tc->range++;
 | 
						|
      tc->format |= PNG_FORMAT_FLAG_RANGE;
 | 
						|
 | 
						|
      if (tc->init == PNG_TC_INIT_FINAL)
 | 
						|
      {
 | 
						|
#     ifdef PNG_READ_SHIFT_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            (*transform)->fn = png_do_unshift;
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifdef PNG_WRITE_SHIFT_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            (*transform)->fn = png_do_shift;
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   else /* transform not applicable */
 | 
						|
      (*transform)->fn = NULL;
 | 
						|
}
 | 
						|
 | 
						|
void PNGAPI
 | 
						|
png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL && true_bits != NULL)
 | 
						|
   {
 | 
						|
#     ifndef PNG_READ_SHIFT_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_shift not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_SHIFT_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_shift not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      {
 | 
						|
         png_transform_shift *trs = png_transform_cast(png_transform_shift,
 | 
						|
            png_add_transform(png_ptr, sizeof (png_transform_shift),
 | 
						|
               init_shift, PNG_TR_SHIFT));
 | 
						|
         trs->true_bits = *true_bits;
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* SHIFT */
 | 
						|
 | 
						|
#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
 | 
						|
/* Turn on pixel packing */
 | 
						|
void PNGAPI
 | 
						|
png_set_packing(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* The transforms aren't symmetric, so even though there is one API there are
 | 
						|
    * two internal init functions, one for read, the other write:
 | 
						|
    */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
      {
 | 
						|
#        ifdef PNG_READ_PACK_SUPPORTED
 | 
						|
            png_add_transform(png_ptr, 0/*size*/, png_init_read_pack,
 | 
						|
               PNG_TR_PACK);
 | 
						|
#        else
 | 
						|
            png_app_error(png_ptr, "png_set_packing not supported on read");
 | 
						|
#        endif
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
      {
 | 
						|
#        ifdef PNG_WRITE_PACK_SUPPORTED
 | 
						|
            png_add_transform(png_ptr, 0/*size*/, png_init_write_pack,
 | 
						|
               PNG_TR_PACK);
 | 
						|
#        else
 | 
						|
            png_app_error(png_ptr, "png_set_packing not supported on write");
 | 
						|
#        endif
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* PACK */
 | 
						|
 | 
						|
#if defined(PNG_READ_PACKSWAP_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_PACKSWAP_SUPPORTED)
 | 
						|
/* Turn on pixel-swapping within a byte, this is symmetric - doing the swap
 | 
						|
 * twice produces the original value, so only one implementation is required for
 | 
						|
 * either read or write.
 | 
						|
 *
 | 
						|
 * Used to be refered to as "packswap", but pixel-swap seems more
 | 
						|
 * self-documenting.
 | 
						|
 */
 | 
						|
static void
 | 
						|
png_do_swap_1bit(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_alloc_size_t rowbytes = row_align(tc); /* may change tc->sp */
 | 
						|
   png_const_uint_32p sp = png_voidcast(png_const_uint_32p, tc->sp);
 | 
						|
   png_uint_32p dp = png_voidcast(png_uint_32p, tc->dp);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
   tc->format ^= PNG_FORMAT_FLAG_SWAPPED;
 | 
						|
 | 
						|
   for (;;)
 | 
						|
   {
 | 
						|
      png_uint_32 s = *sp++;
 | 
						|
      s = ((s >> 1) & 0x55555555) | ((s & 0x55555555) << 1);
 | 
						|
      s = ((s >> 2) & 0x33333333) | ((s & 0x33333333) << 2);
 | 
						|
      s = ((s >> 4) & 0x0f0f0f0f) | ((s & 0x0f0f0f0f) << 4);
 | 
						|
      *dp++ = s;
 | 
						|
      if (rowbytes <= 4) break;
 | 
						|
      rowbytes -= 4;
 | 
						|
   }
 | 
						|
 | 
						|
   PNG_UNUSED(transform)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_swap_2bit(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_alloc_size_t rowbytes = row_align(tc); /* may change tc->sp */
 | 
						|
   png_const_uint_32p sp = png_voidcast(png_const_uint_32p, tc->sp);
 | 
						|
   png_uint_32p dp = png_voidcast(png_uint_32p, tc->dp);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
   tc->format ^= PNG_FORMAT_FLAG_SWAPPED;
 | 
						|
 | 
						|
   for (;;)
 | 
						|
   {
 | 
						|
      png_uint_32 s = *sp++;
 | 
						|
      s = ((s >> 2) & 0x33333333) | ((s & 0x33333333) << 2);
 | 
						|
      s = ((s >> 4) & 0x0f0f0f0f) | ((s & 0x0f0f0f0f) << 4);
 | 
						|
      *dp++ = s;
 | 
						|
      if (rowbytes <= 4) break;
 | 
						|
      rowbytes -= 4;
 | 
						|
   }
 | 
						|
 | 
						|
   PNG_UNUSED(transform)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
png_do_swap_4bit(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_alloc_size_t rowbytes = row_align(tc); /* may change tc->sp */
 | 
						|
   png_const_uint_32p sp = png_voidcast(png_const_uint_32p, tc->sp);
 | 
						|
   png_uint_32p dp = png_voidcast(png_uint_32p, tc->dp);
 | 
						|
 | 
						|
   tc->sp = dp;
 | 
						|
   tc->format ^= PNG_FORMAT_FLAG_SWAPPED;
 | 
						|
 | 
						|
   for (;;)
 | 
						|
   {
 | 
						|
      png_uint_32 s = *sp++;
 | 
						|
      s = ((s >> 4) & 0x0f0f0f0f) | ((s & 0x0f0f0f0f) << 4);
 | 
						|
      *dp++ = s;
 | 
						|
      if (rowbytes <= 4) break;
 | 
						|
      rowbytes -= 4;
 | 
						|
   }
 | 
						|
 | 
						|
   PNG_UNUSED(transform)
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
init_packswap(png_transformp *transform, png_transform_controlp tc)
 | 
						|
{
 | 
						|
   png_transform_fn fn;
 | 
						|
 | 
						|
#  define png_ptr tc->png_ptr
 | 
						|
   debug(tc->init);
 | 
						|
#  undef png_ptr
 | 
						|
 | 
						|
   switch (tc->bit_depth)
 | 
						|
   {
 | 
						|
      case 1: fn = png_do_swap_1bit; break;
 | 
						|
      case 2: fn = png_do_swap_2bit; break;
 | 
						|
      case 4: fn = png_do_swap_4bit; break;
 | 
						|
 | 
						|
      default: /* transform not applicable */
 | 
						|
         (*transform)->fn = NULL;
 | 
						|
         return;
 | 
						|
   }
 | 
						|
 | 
						|
   tc->format ^= PNG_FORMAT_FLAG_SWAPPED;
 | 
						|
   if (tc->init == PNG_TC_INIT_FINAL)
 | 
						|
      (*transform)->fn = fn;
 | 
						|
}
 | 
						|
 | 
						|
void PNGAPI
 | 
						|
png_set_packswap(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
#     ifndef PNG_READ_PACKSWAP_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_packswap not supported on read");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
#     ifndef PNG_WRITE_PACKSWAP_SUPPORTED
 | 
						|
         if (!png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            png_app_error(png_ptr, "png_set_packswap not supported on write");
 | 
						|
            return;
 | 
						|
         }
 | 
						|
#     endif
 | 
						|
 | 
						|
      png_add_transform(png_ptr, 0/*size*/, init_packswap, PNG_TR_PIXEL_SWAP);
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* PACKSWAP */
 | 
						|
 | 
						|
/* User transform handling */
 | 
						|
#ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED
 | 
						|
png_uint_32 PNGAPI
 | 
						|
png_get_current_row_number(png_const_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* See the comments in png.h - this is the sub-image row when reading an
 | 
						|
    * interlaced image.
 | 
						|
    */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      /* In the read case png_struct::row_number is the row in the final image,
 | 
						|
       * not the pass, this will return the previous row number if the row isn't
 | 
						|
       * in the pass:
 | 
						|
       */
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
         return PNG_PASS_ROWS(png_ptr->row_number+1, png_ptr->pass)-1U;
 | 
						|
 | 
						|
      else
 | 
						|
         return png_ptr->row_number;
 | 
						|
   }
 | 
						|
 | 
						|
   return PNG_UINT_32_MAX; /* help the app not to fail silently */
 | 
						|
}
 | 
						|
 | 
						|
png_byte PNGAPI
 | 
						|
png_get_current_pass_number(png_const_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
      return png_ptr->pass;
 | 
						|
   return 8; /* invalid */
 | 
						|
}
 | 
						|
#endif /* USER_TRANSFORM_INFO */
 | 
						|
 | 
						|
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) ||\
 | 
						|
    defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
 | 
						|
typedef struct
 | 
						|
{
 | 
						|
   png_transform          tr;
 | 
						|
   png_user_transform_ptr user_fn;
 | 
						|
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 | 
						|
   png_voidp              user_ptr;
 | 
						|
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
 | 
						|
   unsigned int           user_depth;
 | 
						|
   unsigned int           user_channels;
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
}  png_user_transform, *png_user_transformp;
 | 
						|
 | 
						|
typedef const png_user_transform *png_const_user_transformp;
 | 
						|
 | 
						|
static png_user_transformp
 | 
						|
get_user_transform(png_structrp png_ptr)
 | 
						|
{
 | 
						|
   /* Note that in an added transform the whole transform is memset to 0, so we
 | 
						|
    * don't need to initialize anything.
 | 
						|
    */
 | 
						|
   return png_transform_cast(png_user_transform, png_add_transform(png_ptr,
 | 
						|
      sizeof (png_user_transform), NULL/*function*/, PNG_TR_USER));
 | 
						|
}
 | 
						|
#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */
 | 
						|
 | 
						|
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 | 
						|
png_voidp PNGAPI
 | 
						|
png_get_user_transform_ptr(png_const_structrp png_ptr)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      png_transformp tr = png_find_transform(png_ptr, PNG_TR_USER);
 | 
						|
 | 
						|
      if (tr != NULL)
 | 
						|
      {
 | 
						|
         png_user_transformp tru = png_transform_cast(png_user_transform, tr);
 | 
						|
         return tru->user_ptr;
 | 
						|
      }
 | 
						|
   }
 | 
						|
 | 
						|
   return NULL;
 | 
						|
}
 | 
						|
#endif /* USER_TRANSFORM_PTR */
 | 
						|
 | 
						|
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 | 
						|
void PNGAPI
 | 
						|
png_set_user_transform_info(png_structrp png_ptr, png_voidp ptr, int depth,
 | 
						|
   int channels)
 | 
						|
{
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      /* NOTE: this function only sets the user transform pointer on write, i.e.
 | 
						|
       * the depth and channels arguments are ignored.
 | 
						|
       */
 | 
						|
      png_user_transformp tr = get_user_transform(png_ptr);
 | 
						|
 | 
						|
      tr->user_ptr = ptr;
 | 
						|
 | 
						|
#     ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
 | 
						|
         if (png_ptr->read_struct)
 | 
						|
         {
 | 
						|
            if (png_ptr->row_bit_depth == 0)
 | 
						|
            {
 | 
						|
               if (depth > 0 && depth <= 32 && channels > 0 && channels <= 4 &&
 | 
						|
                   (-depth & depth) == depth /* power of 2 */)
 | 
						|
               {
 | 
						|
                  tr->user_depth = png_check_bits(png_ptr, depth, 6);
 | 
						|
                  tr->user_channels = png_check_bits(png_ptr, channels, 3);
 | 
						|
               }
 | 
						|
 | 
						|
               else
 | 
						|
                  png_app_error(png_ptr, "unsupported bit-depth or channels");
 | 
						|
            }
 | 
						|
            else
 | 
						|
               png_app_error(png_ptr,
 | 
						|
                  "cannot change user info after image start");
 | 
						|
         }
 | 
						|
#     else /* !READ_USER_TRANSFORM */
 | 
						|
         PNG_UNUSED(depth)
 | 
						|
         PNG_UNUSED(channels)
 | 
						|
#     endif /* !READ_USER_TRANSFORM */
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* USER_TRANSFORM_PTR */
 | 
						|
 | 
						|
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
 | 
						|
static void
 | 
						|
png_do_read_user_transform(png_transformp *trIn, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   png_user_transformp tr = png_transform_cast(png_user_transform, *trIn);
 | 
						|
 | 
						|
   if (!tc->init && tr->user_fn != NULL)
 | 
						|
   {
 | 
						|
      png_row_info row_info;
 | 
						|
 | 
						|
      row_info.width = tc->width;
 | 
						|
      row_info.rowbytes = PNG_TC_ROWBYTES(*tc);
 | 
						|
      row_info.color_type = png_check_byte(png_ptr,
 | 
						|
         PNG_COLOR_TYPE_FROM_FORMAT(tc->format));
 | 
						|
      row_info.bit_depth = png_check_byte(png_ptr, tc->bit_depth);
 | 
						|
      row_info.channels = png_check_byte(png_ptr,
 | 
						|
         PNG_FORMAT_CHANNELS(tc->format));
 | 
						|
      row_info.bit_depth = png_check_byte(png_ptr,
 | 
						|
         PNG_TC_PIXEL_DEPTH(*tc));
 | 
						|
 | 
						|
      /* TODO: fix this API, but for the moment we have to copy the row data to
 | 
						|
       * the working buffer.  This is an unnecessary perf overhead when a user
 | 
						|
       * transform is used to read information without a transform or when it is
 | 
						|
       * used on write.
 | 
						|
       */
 | 
						|
      if (tc->sp != tc->dp)
 | 
						|
      {
 | 
						|
         memcpy(tc->dp, tc->sp, PNG_TC_ROWBYTES(*tc));
 | 
						|
         tc->sp = tc->dp;
 | 
						|
      }
 | 
						|
 | 
						|
      tr->user_fn(png_ptr, &row_info, png_voidcast(png_bytep, tc->dp));
 | 
						|
   }
 | 
						|
 | 
						|
#  ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
 | 
						|
      if (tr->user_depth > 0)
 | 
						|
      {
 | 
						|
         /* The read transform can modify the bit depth and number of
 | 
						|
          * channels; the interface doesn't permit anything else to be
 | 
						|
          * changed.  If the information isn't set the user callback has to
 | 
						|
          * produce pixels with the correct pixel depth (otherwise the
 | 
						|
          * de-interlace won't work) but there really is no other constraint.
 | 
						|
          */
 | 
						|
         tc->bit_depth = tr->user_depth;
 | 
						|
 | 
						|
         /* The API is very restricted in functionality; the user_channels
 | 
						|
          * can be changed, but the color_type can't, so the format is simply
 | 
						|
          * fixed up to match the channels.
 | 
						|
          */
 | 
						|
         if (tr->user_channels != PNG_FORMAT_CHANNELS(tc->format))
 | 
						|
            switch (tr->user_channels)
 | 
						|
         {
 | 
						|
            case 1:
 | 
						|
               tc->format &=
 | 
						|
                  PNG_BIC_MASK(PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA);
 | 
						|
               break;
 | 
						|
 | 
						|
            case 2: /* has to be GA */
 | 
						|
               tc->format &=
 | 
						|
                  PNG_BIC_MASK(PNG_FORMAT_FLAG_COLORMAP+PNG_FORMAT_FLAG_COLOR);
 | 
						|
               tc->format |= PNG_FORMAT_FLAG_ALPHA;
 | 
						|
               break;
 | 
						|
 | 
						|
            case 3: /* has to be RGB */
 | 
						|
               tc->format &=
 | 
						|
                  PNG_BIC_MASK(PNG_FORMAT_FLAG_COLORMAP|PNG_FORMAT_FLAG_ALPHA);
 | 
						|
               tc->format |= PNG_FORMAT_FLAG_COLOR;
 | 
						|
               break;
 | 
						|
 | 
						|
            case 4: /* has to be RGBA */
 | 
						|
               tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_COLORMAP);
 | 
						|
               tc->format |= (PNG_FORMAT_FLAG_COLOR+PNG_FORMAT_FLAG_ALPHA);
 | 
						|
               break;
 | 
						|
 | 
						|
            default: /* checked before */
 | 
						|
               impossible("user channels");
 | 
						|
         }
 | 
						|
 | 
						|
         debug(PNG_FORMAT_CHANNELS(tc->format) == tr->user_channels);
 | 
						|
      }
 | 
						|
#  endif /* USER_TRANSFORM_PTR */
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
 | 
						|
void PNGAPI
 | 
						|
png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
 | 
						|
    read_user_transform_fn)
 | 
						|
{
 | 
						|
   /* There is no 'init' function, just the callback above to handle the
 | 
						|
    * transform.
 | 
						|
    */
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      if (png_ptr->read_struct)
 | 
						|
      {
 | 
						|
         png_user_transformp tr = get_user_transform(png_ptr);
 | 
						|
 | 
						|
         tr->user_fn = read_user_transform_fn;
 | 
						|
         tr->tr.fn = png_do_read_user_transform;
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
         png_app_error(png_ptr, "cannot set a read transform on write");
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* READ_USER_TRANSFORM */
 | 
						|
 | 
						|
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
 | 
						|
static void
 | 
						|
png_do_write_user_transform(png_transformp *trIn, png_transform_controlp tc)
 | 
						|
{
 | 
						|
#  define png_ptr (tc->png_ptr)
 | 
						|
   /* The write side is pretty simple; call the call-back, it will make the row
 | 
						|
    * data right.
 | 
						|
    *
 | 
						|
    * BUG: we need to copy the input row (it would be a non-quiet API change
 | 
						|
    * otherwise) and we don't know how big it is because the information passed
 | 
						|
    * to png_set_user_transform_info never was used on write, but that's fine
 | 
						|
    * because the write code never did get this right, so presumably all the
 | 
						|
    * apps have worked round it...
 | 
						|
    */
 | 
						|
   if (!tc->init)
 | 
						|
   {
 | 
						|
      png_user_transformp tr = png_transform_cast(png_user_transform, *trIn);
 | 
						|
      png_row_info row_info;
 | 
						|
 | 
						|
      if (tc->sp != tc->dp) /* no interlace */
 | 
						|
      {
 | 
						|
         memcpy(tc->dp, tc->sp, PNG_TC_ROWBYTES(*tc));
 | 
						|
         tc->sp = tc->dp;
 | 
						|
      }
 | 
						|
 | 
						|
      row_info.width = tc->width;
 | 
						|
      row_info.rowbytes = PNG_TC_ROWBYTES(*tc);
 | 
						|
      row_info.color_type = png_check_byte(png_ptr,
 | 
						|
         PNG_COLOR_TYPE_FROM_FORMAT(tc->format));
 | 
						|
      row_info.bit_depth = png_check_byte(png_ptr, tc->bit_depth);
 | 
						|
      row_info.channels = png_check_byte(png_ptr,
 | 
						|
         PNG_FORMAT_CHANNELS(tc->format));
 | 
						|
      row_info.bit_depth = png_check_byte(png_ptr,
 | 
						|
         PNG_TC_PIXEL_DEPTH(*tc));
 | 
						|
 | 
						|
      /* The user function promises to give us this format: */
 | 
						|
      tr->user_fn(png_ptr, &row_info, png_voidcast(png_bytep, tc->dp));
 | 
						|
   }
 | 
						|
#  undef png_ptr
 | 
						|
}
 | 
						|
 | 
						|
void PNGAPI
 | 
						|
png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
 | 
						|
    write_user_transform_fn)
 | 
						|
{
 | 
						|
 | 
						|
   if (png_ptr != NULL)
 | 
						|
   {
 | 
						|
      if (!png_ptr->read_struct)
 | 
						|
      {
 | 
						|
         png_user_transformp tr = get_user_transform(png_ptr);
 | 
						|
 | 
						|
         tr->user_fn = write_user_transform_fn;
 | 
						|
         tr->tr.fn = png_do_write_user_transform;
 | 
						|
      }
 | 
						|
 | 
						|
      else
 | 
						|
         png_app_error(png_ptr, "cannot set a write transform on read");
 | 
						|
   }
 | 
						|
}
 | 
						|
#endif /* WRITE_USER_TRANSFORM */
 |