all repos — mgba @ b03412aa38b39190f475cb89d5c8a2a5e97bc32d

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/libtests/pngimage.c (view raw)

   1/* pngimage.c
   2 *
   3 * Copyright (c) 2014 John Cunningham Bowler
   4 *
   5 * Last changed in libpng 1.6.10 [March 6, 2014]
   6 *
   7 * This code is released under the libpng license.
   8 * For conditions of distribution and use, see the disclaimer
   9 * and license in png.h
  10 *
  11 * Test the png_read_png and png_write_png interfaces.  Given a PNG file load it
  12 * using png_read_png and then write with png_write_png.  Test all possible
  13 * transforms.
  14 */
  15#include <stdarg.h>
  16#include <stdlib.h>
  17#include <string.h>
  18#include <errno.h>
  19#include <stdio.h>
  20#include <assert.h>
  21
  22#if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
  23#  include <config.h>
  24#endif
  25
  26/* Define the following to use this test against your installed libpng, rather
  27 * than the one being built here:
  28 */
  29#ifdef PNG_FREESTANDING_TESTS
  30#  include <png.h>
  31#else
  32#  include "../../png.h"
  33#endif
  34
  35#ifndef PNG_SETJMP_SUPPORTED
  36#  include <setjmp.h> /* because png.h did *not* include this */
  37#endif
  38
  39#if defined(PNG_INFO_IMAGE_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
  40/* If a transform is valid on both read and write this implies that if the
  41 * transform is applied to read it must also be applied on write to produce
  42 * meaningful data.  This is because these transforms when performed on read
  43 * produce data with a memory format that does not correspond to a PNG format.
  44 *
  45 * Most of these transforms are invertible; after applying the transform on
  46 * write the result is the original PNG data that would have would have been
  47 * read if no transform were applied.
  48 *
  49 * The exception is _SHIFT, which destroys the low order bits marked as not
  50 * significant in a PNG with the sBIT chunk.
  51 *
  52 * The following table lists, for each transform, the conditions under which it
  53 * is expected to do anything.  Conditions are defined as follows:
  54 *
  55 * 1) Color mask bits required - simply a mask to AND with color_type; one of
  56 *    these must be present for the transform to fire, except that 0 means
  57 *    'always'.
  58 * 2) Color mask bits which must be absent - another mask - none of these must
  59 *    be present.
  60 * 3) Bit depths - a mask of component bit depths for the transform to fire.
  61 * 4) 'read' - the transform works in png_read_png.
  62 * 5) 'write' - the transform works in png_write_png.
  63 * 6) PNG_INFO_chunk; a mask of the chunks that must be present for the
  64 *    transform to fire.  All must be present - the requirement is that
  65 *    png_get_valid() & mask == mask, so if mask is 0 there is no requirement.
  66 *
  67 * The condition refers to the original image state - if multiple transforms are
  68 * used together it is possible to cause a transform that wouldn't fire on the
  69 * original image to fire.
  70 */
  71static struct transform_info
  72{
  73   const char *name;
  74   int         transform;
  75   png_uint_32 valid_chunks;
  76#     define CHUNK_NONE 0
  77#     define CHUNK_sBIT PNG_INFO_sBIT
  78#     define CHUNK_tRNS PNG_INFO_tRNS
  79   png_byte    color_mask_required;
  80   png_byte    color_mask_absent;
  81#     define COLOR_MASK_X   0
  82#     define COLOR_MASK_P   PNG_COLOR_MASK_PALETTE
  83#     define COLOR_MASK_C   PNG_COLOR_MASK_COLOR
  84#     define COLOR_MASK_A   PNG_COLOR_MASK_ALPHA
  85#     define COLOR_MASK_ALL (PALETTE+COLOR+ALPHA)  /* absent = gray, no alpha */
  86   png_byte    bit_depths;
  87#     define BD_ALL  (1 + 2 + 4 + 8 + 16)
  88#     define BD_PAL  (1 + 2 + 4 + 8)
  89#     define BD_LOW  (1 + 2 + 4)
  90#     define BD_16   16
  91#     define BD_TRUE (8+16) /* i.e. true-color depths */
  92   png_byte    when;
  93#     define TRANSFORM_R  1
  94#     define TRANSFORM_W  2
  95#     define TRANSFORM_RW 3
  96   png_byte    tested; /* the transform was tested somewhere */
  97} transform_info[] =
  98{
  99   /* List ALL the PNG_TRANSFORM_ macros here.  Check for support using the READ
 100    * macros; even if the transform is supported on write it cannot be tested
 101    * without the read support.
 102    */
 103#  define T(name,chunk,cm_required,cm_absent,bd,when)\
 104   {  #name, PNG_TRANSFORM_ ## name, CHUNK_ ## chunk,\
 105      COLOR_MASK_ ## cm_required, COLOR_MASK_ ## cm_absent, BD_ ## bd,\
 106      TRANSFORM_ ## when, 0/*!tested*/ }
 107
 108#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
 109   T(STRIP_16,            NONE, X,   X,   16,  R),
 110      /* drops the bottom 8 bits when bit depth is 16 */
 111#endif
 112#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
 113   T(STRIP_ALPHA,         NONE, A,   X,  ALL,  R),
 114      /* removes the alpha channel if present */
 115#endif
 116#ifdef PNG_WRITE_PACK_SUPPORTED
 117#  define TRANSFORM_RW_PACK TRANSFORM_RW
 118#else
 119#  define TRANSFORM_RW_PACK TRANSFORM_R
 120#endif
 121#ifdef PNG_READ_PACK_SUPPORTED
 122   T(PACKING,             NONE, X,   X,  LOW, RW_PACK),
 123      /* unpacks low-bit-depth components into 1 byte per component on read,
 124       * reverses this on write.
 125       */
 126#endif
 127#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
 128#  define TRANSFORM_RW_PACKSWAP TRANSFORM_RW
 129#else
 130#  define TRANSFORM_RW_PACKSWAP TRANSFORM_R
 131#endif
 132#ifdef PNG_READ_PACKSWAP_SUPPORTED
 133   T(PACKSWAP,            NONE, X,   X,  LOW, RW_PACKSWAP),
 134      /* reverses the order of low-bit-depth components packed into a byte */
 135#endif
 136#ifdef PNG_READ_EXPAND_SUPPORTED
 137   T(EXPAND,              NONE, P,   X,  ALL,  R),
 138      /* expands PLTE PNG files to RGB (no tRNS) or RGBA (tRNS) *
 139       * Note that the 'EXPAND' transform does lots of different things: */
 140   T(EXPAND,              NONE, X,   C,  ALL,  R),
 141      /* expands grayscale PNG files to RGB, or RGBA */
 142   T(EXPAND,              tRNS, X,   A,  ALL,  R),
 143      /* expands the tRNS chunk in files without alpha */
 144#endif
 145#ifdef PNG_WRITE_INVERT_SUPPORTED
 146#  define TRANSFORM_RW_INVERT TRANSFORM_RW
 147#else
 148#  define TRANSFORM_RW_INVERT TRANSFORM_R
 149#endif
 150#ifdef PNG_READ_INVERT_SUPPORTED
 151   T(INVERT_MONO,         NONE, X,   C,  ALL, RW_INVERT),
 152      /* converts gray-scale components to 1..0 from 0..1 */
 153#endif
 154#ifdef PNG_WRITE_SHIFT_SUPPORTED
 155#  define TRANSFORM_RW_SHIFT TRANSFORM_RW
 156#else
 157#  define TRANSFORM_RW_SHIFT TRANSFORM_R
 158#endif
 159#ifdef PNG_READ_SHIFT_SUPPORTED
 160   T(SHIFT,               sBIT, X,   X,  ALL, RW_SHIFT),
 161      /* reduces component values to the original range based on the sBIT chunk,
 162       * this is only partially reversible - the low bits are lost and cannot be
 163       * recovered on write.  In fact write code replicates the bits to generate
 164       * new low-order bits.
 165       */
 166#endif
 167#ifdef PNG_WRITE_BGR_SUPPORTED
 168#  define TRANSFORM_RW_BGR TRANSFORM_RW
 169#else
 170#  define TRANSFORM_RW_BGR TRANSFORM_R
 171#endif
 172#ifdef PNG_READ_BGR_SUPPORTED
 173   T(BGR,                 NONE, C,   P, TRUE, RW_BGR),
 174      /* reverses the rgb component values of true-color pixels */
 175#endif
 176#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED
 177#  define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_RW
 178#else
 179#  define TRANSFORM_RW_SWAP_ALPHA TRANSFORM_R
 180#endif
 181#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
 182   T(SWAP_ALPHA,          NONE, A,   X, TRUE, RW_SWAP_ALPHA),
 183      /* swaps the alpha channel of RGBA or GA pixels to the front - ARGB or
 184       * AG, on write reverses the process.
 185       */
 186#endif
 187#ifdef PNG_WRITE_SWAP_SUPPORTED
 188#  define TRANSFORM_RW_SWAP TRANSFORM_RW
 189#else
 190#  define TRANSFORM_RW_SWAP TRANSFORM_R
 191#endif
 192#ifdef PNG_READ_SWAP_SUPPORTED
 193   T(SWAP_ENDIAN,         NONE, X,   P,   16, RW_SWAP),
 194      /* byte-swaps 16-bit component values */
 195#endif
 196#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED
 197#  define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_RW
 198#else
 199#  define TRANSFORM_RW_INVERT_ALPHA TRANSFORM_R
 200#endif
 201#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
 202   T(INVERT_ALPHA,        NONE, A,   X, TRUE, RW_INVERT_ALPHA),
 203      /* converts an alpha channel from 0..1 to 1..0 */
 204#endif
 205#ifdef PNG_WRITE_FILLER_SUPPORTED
 206   T(STRIP_FILLER_BEFORE, NONE, A,   P, TRUE,  W), /* 'A' for a filler! */
 207      /* on write skips a leading filler channel; testing requires data with a
 208       * filler channel so this is produced from RGBA or GA images by removing
 209       * the 'alpha' flag from the color type in place.
 210       */
 211   T(STRIP_FILLER_AFTER,  NONE, A,   P, TRUE,  W),
 212      /* on write strips a trailing filler channel */
 213#endif
 214#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
 215   T(GRAY_TO_RGB,         NONE, X,   C,  ALL,  R),
 216      /* expands grayscale images to RGB, also causes the palette part of
 217       * 'EXPAND' to happen.  Low bit depth grayscale images are expanded to
 218       * 8-bits per component and no attempt is made to convert the image to a
 219       * palette image.  While this transform is partially reversible
 220       * png_write_png does not currently support this.
 221       */
 222   T(GRAY_TO_RGB,         NONE, P,   X,  ALL,  R),
 223      /* The 'palette' side effect mentioned above; a bit bogus but this is the
 224       * way the libpng code works.
 225       */
 226#endif
 227#ifdef PNG_READ_EXPAND_16_SUPPORTED
 228   T(EXPAND_16,           NONE, X,   X,  PAL,  R),
 229      /* expands images to 16-bits per component, as a side effect expands
 230       * palette images to RGB and expands the tRNS chunk if present, so it can
 231       * modify 16-bit per component images as well:
 232       */
 233   T(EXPAND_16,           tRNS, X,   A,   16,  R),
 234      /* side effect of EXPAND_16 - expands the tRNS chunk in an RGB or G 16-bit
 235       * image.
 236       */
 237#endif
 238#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
 239   T(SCALE_16,            NONE, X,   X,   16,  R)
 240      /* scales 16-bit components to 8-bits. */
 241#endif
 242
 243#undef T
 244};
 245
 246#define ARRAY_SIZE(a) ((sizeof a)/(sizeof a[0]))
 247#define TTABLE_SIZE ARRAY_SIZE(transform_info)
 248
 249/* Some combinations of options that should be reversible are not; these cases
 250 * are bugs.
 251 */
 252static int known_bad_combos[][2] =
 253{
 254   /* problem, antidote */
 255   { PNG_TRANSFORM_SHIFT | PNG_TRANSFORM_INVERT_ALPHA, 0/*antidote*/ }
 256};
 257
 258static int
 259is_combo(int transforms)
 260{
 261   return transforms & (transforms-1); /* non-zero if more than one set bit */
 262}
 263
 264static int
 265first_transform(int transforms)
 266{
 267   return transforms & -transforms; /* lowest set bit */
 268}
 269
 270static int
 271is_bad_combo(int transforms)
 272{
 273   unsigned int i;
 274
 275   for (i=0; i<ARRAY_SIZE(known_bad_combos); ++i)
 276   {
 277      int combo = known_bad_combos[i][0];
 278
 279      if ((combo & transforms) == combo &&
 280         (transforms & known_bad_combos[i][1]) == 0)
 281         return 1;
 282   }
 283
 284   return 0; /* combo is ok */
 285}
 286
 287static const char *
 288transform_name(int t)
 289   /* The name, if 't' has multiple bits set the name of the lowest set bit is
 290    * returned.
 291    */
 292{
 293   unsigned int i;
 294
 295   t &= -t; /* first set bit */
 296
 297   for (i=0; i<TTABLE_SIZE; ++i)
 298   {
 299      if ((transform_info[i].transform & t) != 0)
 300         return transform_info[i].name;
 301   }
 302
 303   return "invalid transform";
 304}
 305
 306/* Variables calculated by validate_T below and used to record all the supported
 307 * transforms.  Need (unsigned int) here because of the places where these
 308 * values are used (unsigned compares in the 'exhaustive' iterator.)
 309 */
 310static unsigned int read_transforms, write_transforms, rw_transforms;
 311
 312static void
 313validate_T(void)
 314   /* Validate the above table - this just builds the above values */
 315{
 316   unsigned int i;
 317
 318   for (i=0; i<TTABLE_SIZE; ++i)
 319   {
 320      if (transform_info[i].when & TRANSFORM_R)
 321         read_transforms |= transform_info[i].transform;
 322
 323      if (transform_info[i].when & TRANSFORM_W)
 324         write_transforms |= transform_info[i].transform;
 325   }
 326
 327   /* Reversible transforms are those which are supported on both read and
 328    * write.
 329    */
 330   rw_transforms = read_transforms & write_transforms;
 331}
 332
 333/* FILE DATA HANDLING
 334 *    The original file is cached in memory.  During write the output file is
 335 *    written to memory.
 336 *
 337 *    In both cases the file data is held in a linked list of buffers - not all
 338 *    of these are in use at any time.
 339 */
 340#define NEW(type) ((type *)malloc(sizeof (type)))
 341#define DELETE(ptr) (free(ptr))
 342
 343struct buffer_list
 344{
 345   struct buffer_list *next;         /* next buffer in list */
 346   png_byte            buffer[1024]; /* the actual buffer */
 347};
 348
 349struct buffer
 350{
 351   struct buffer_list  *last;       /* last buffer in use */
 352   size_t               end_count;  /* bytes in the last buffer */
 353   struct buffer_list  *current;    /* current buffer being read */
 354   size_t               read_count; /* count of bytes read from current */
 355   struct buffer_list   first;      /* the very first buffer */
 356};
 357
 358static void
 359buffer_init(struct buffer *buffer)
 360   /* Call this only once for a given buffer */
 361{
 362   buffer->first.next = NULL;
 363   buffer->last = NULL;
 364   buffer->current = NULL;
 365}
 366
 367static void
 368buffer_destroy_list(struct buffer_list *list)
 369{
 370   if (list != NULL)
 371   {
 372      struct buffer_list *next = list->next;
 373      DELETE(list);
 374      buffer_destroy_list(next);
 375   }
 376}
 377
 378static void
 379buffer_destroy(struct buffer *buffer)
 380{
 381   struct buffer_list *list = buffer->first.next;
 382   buffer_init(buffer);
 383   buffer_destroy_list(list);
 384}
 385
 386#ifdef PNG_WRITE_SUPPORTED
 387static void
 388buffer_start_write(struct buffer *buffer)
 389{
 390   buffer->last = &buffer->first;
 391   buffer->end_count = 0;
 392   buffer->current = NULL;
 393}
 394#endif
 395
 396static void
 397buffer_start_read(struct buffer *buffer)
 398{
 399   buffer->current = &buffer->first;
 400   buffer->read_count = 0;
 401}
 402
 403#ifdef ENOMEM /* required by POSIX 1003.1 */
 404#  define MEMORY ENOMEM
 405#else
 406#  define MEMORY ERANGE /* required by ANSI-C */
 407#endif
 408static struct buffer *
 409get_buffer(png_structp pp)
 410   /* Used from libpng callbacks to get the current buffer */
 411{
 412   return (struct buffer*)png_get_io_ptr(pp);
 413}
 414
 415static struct buffer_list *
 416buffer_extend(struct buffer_list *current)
 417{
 418   struct buffer_list *add;
 419
 420   assert(current->next == NULL);
 421
 422   add = NEW(struct buffer_list);
 423   if (add == NULL)
 424      return NULL;
 425
 426   add->next = NULL;
 427   current->next = add;
 428
 429   return add;
 430}
 431
 432/* Load a buffer from a file; does the equivalent of buffer_start_write.  On a
 433 * read error returns an errno value, else returns 0.
 434 */
 435static int
 436buffer_from_file(struct buffer *buffer, FILE *fp)
 437{
 438   struct buffer_list *last = &buffer->first;
 439   size_t count = 0;
 440
 441   for (;;)
 442   {
 443      size_t r = fread(last->buffer+count, 1/*size*/,
 444         (sizeof last->buffer)-count, fp);
 445
 446      if (r > 0)
 447      {
 448         count += r;
 449
 450         if (count >= sizeof last->buffer)
 451         {
 452            assert(count == sizeof last->buffer);
 453            count = 0;
 454
 455            if (last->next == NULL)
 456            {
 457               last = buffer_extend(last);
 458               if (last == NULL)
 459                  return MEMORY;
 460            }
 461
 462            else
 463               last = last->next;
 464         }
 465      }
 466
 467      else /* fread failed - probably end of file */
 468      {
 469         if (feof(fp))
 470         {
 471            buffer->last = last;
 472            buffer->end_count = count;
 473            return 0; /* no error */
 474         }
 475
 476         /* Some kind of funky error; errno should be non-zero */
 477         return errno == 0 ? ERANGE : errno;
 478      }
 479   }
 480}
 481
 482/* This structure is used to control the test of a single file. */
 483typedef enum
 484{
 485   VERBOSE,        /* switches on all messages */
 486   INFORMATION,
 487   WARNINGS,       /* switches on warnings */
 488   LIBPNG_WARNING,
 489   APP_WARNING,
 490   ERRORS,         /* just errors */
 491   APP_FAIL,       /* continuable error - no need to longjmp */
 492   LIBPNG_ERROR,   /* this and higher cause a longjmp */
 493   LIBPNG_BUG,     /* erroneous behavior in libpng */
 494   APP_ERROR,      /* such as out-of-memory in a callback */
 495   QUIET,          /* no normal messages */
 496   USER_ERROR,     /* such as file-not-found */
 497   INTERNAL_ERROR
 498} error_level;
 499#define LEVEL_MASK      0xf   /* where the level is in 'options' */
 500
 501#define EXHAUSTIVE      0x010 /* Test all combinations of active options */
 502#define STRICT          0x020 /* Fail on warnings as well as errors */
 503#define LOG             0x040 /* Log pass/fail to stdout */
 504#define CONTINUE        0x080 /* Continue on APP_FAIL errors */
 505#define SKIP_BUGS       0x100 /* Skip over known bugs */
 506#define LOG_SKIPPED     0x200 /* Log skipped bugs */
 507#define FIND_BAD_COMBOS 0x400 /* Attempt to deduce bad combos */
 508
 509/* Result masks apply to the result bits in the 'results' field below; these
 510 * bits are simple 1U<<error_level.  A pass requires either nothing worse than
 511 * warnings (--relaxes) or nothing worse than information (--strict)
 512 */
 513#define RESULT_STRICT(r)   (((r) & ~((1U<<WARNINGS)-1)) == 0)
 514#define RESULT_RELAXED(r)  (((r) & ~((1U<<ERRORS)-1)) == 0)
 515
 516struct display
 517{
 518   jmp_buf        error_return;      /* Where to go to on error */
 519
 520   const char    *filename;          /* The name of the original file */
 521   const char    *operation;         /* Operation being performed */
 522   int            transforms;        /* Transform used in operation */
 523   png_uint_32    options;           /* See display_log below */
 524   png_uint_32    results;           /* A mask of errors seen */
 525
 526
 527   png_structp    original_pp;       /* used on the original read */
 528   png_infop      original_ip;       /* set by the original read */
 529
 530   png_size_t     original_rowbytes; /* of the original rows: */
 531   png_bytepp     original_rows;     /* from the original read */
 532
 533   /* Original chunks valid */
 534   png_uint_32    chunks;
 535
 536   /* Original IHDR information */
 537   png_uint_32    width;
 538   png_uint_32    height;
 539   int            bit_depth;
 540   int            color_type;
 541   int            interlace_method;
 542   int            compression_method;
 543   int            filter_method;
 544
 545   /* Derived information for the original image. */
 546   int            active_transforms;  /* transforms that do something on read */
 547   int            ignored_transforms; /* transforms that should do nothing */
 548
 549   /* Used on a read, both the original read and when validating a written
 550    * image.
 551    */
 552   png_structp    read_pp;
 553   png_infop      read_ip;
 554
 555#  ifdef PNG_WRITE_SUPPORTED
 556      /* Used to write a new image (the original info_ptr is used) */
 557      png_structp   write_pp;
 558      struct buffer written_file;   /* where the file gets written */
 559#  endif
 560
 561   struct buffer  original_file;     /* Data read from the original file */
 562};
 563
 564static void
 565display_init(struct display *dp)
 566   /* Call this only once right at the start to initialize the control
 567    * structure, the (struct buffer) lists are maintained across calls - the
 568    * memory is not freed.
 569    */
 570{
 571   memset(dp, 0, sizeof *dp);
 572   dp->options = WARNINGS; /* default to !verbose, !quiet */
 573   dp->filename = NULL;
 574   dp->operation = NULL;
 575   dp->original_pp = NULL;
 576   dp->original_ip = NULL;
 577   dp->original_rows = NULL;
 578   dp->read_pp = NULL;
 579   dp->read_ip = NULL;
 580   buffer_init(&dp->original_file);
 581
 582#  ifdef PNG_WRITE_SUPPORTED
 583      dp->write_pp = NULL;
 584      buffer_init(&dp->written_file);
 585#  endif
 586}
 587
 588static void
 589display_clean_read(struct display *dp)
 590{
 591   if (dp->read_pp != NULL)
 592      png_destroy_read_struct(&dp->read_pp, &dp->read_ip, NULL);
 593}
 594
 595#ifdef PNG_WRITE_SUPPORTED
 596static void
 597display_clean_write(struct display *dp)
 598{
 599      if (dp->write_pp != NULL)
 600         png_destroy_write_struct(&dp->write_pp, NULL);
 601}
 602#endif
 603
 604static void
 605display_clean(struct display *dp)
 606{
 607#  ifdef PNG_WRITE_SUPPORTED
 608      display_clean_write(dp);
 609#  endif
 610   display_clean_read(dp);
 611
 612   dp->original_rowbytes = 0;
 613   dp->original_rows = NULL;
 614   dp->chunks = 0;
 615
 616   png_destroy_read_struct(&dp->original_pp, &dp->original_ip, NULL);
 617   /* leave the filename for error detection */
 618   dp->results = 0; /* reset for next time */
 619}
 620
 621static void
 622display_destroy(struct display *dp)
 623{
 624    /* Release any memory held in the display. */
 625#  ifdef PNG_WRITE_SUPPORTED
 626      buffer_destroy(&dp->written_file);
 627#  endif
 628
 629   buffer_destroy(&dp->original_file);
 630}
 631
 632static struct display *
 633get_dp(png_structp pp)
 634   /* The display pointer is always stored in the png_struct error pointer */
 635{
 636   struct display *dp = (struct display*)png_get_error_ptr(pp);
 637
 638   if (dp == NULL)
 639   {
 640      fprintf(stderr, "pngimage: internal error (no display)\n");
 641      exit(99); /* prevents a crash */
 642   }
 643
 644   return dp;
 645}
 646
 647/* error handling */
 648#ifdef __GNUC__
 649#  define VGATTR __attribute__((__format__ (__printf__,3,4)))
 650   /* Required to quiet GNUC warnings when the compiler sees a stdarg function
 651    * that calls one of the stdio v APIs.
 652    */
 653#else
 654#  define VGATTR
 655#endif
 656static void VGATTR
 657display_log(struct display *dp, error_level level, const char *fmt, ...)
 658   /* 'level' is as above, fmt is a stdio style format string.  This routine
 659    * does not return if level is above LIBPNG_WARNING
 660    */
 661{
 662   dp->results |= 1U << level;
 663
 664   if (level > (error_level)(dp->options & LEVEL_MASK))
 665   {
 666      const char *lp;
 667      va_list ap;
 668
 669      switch (level)
 670      {
 671         case INFORMATION:    lp = "information"; break;
 672         case LIBPNG_WARNING: lp = "warning(libpng)"; break;
 673         case APP_WARNING:    lp = "warning(pngimage)"; break;
 674         case APP_FAIL:       lp = "error(continuable)"; break;
 675         case LIBPNG_ERROR:   lp = "error(libpng)"; break;
 676         case LIBPNG_BUG:     lp = "bug(libpng)"; break;
 677         case APP_ERROR:      lp = "error(pngimage)"; break;
 678         case USER_ERROR:     lp = "error(user)"; break;
 679
 680         case INTERNAL_ERROR: /* anything unexpected is an internal error: */
 681         case VERBOSE: case WARNINGS: case ERRORS: case QUIET:
 682         default:             lp = "bug(pngimage)"; break;
 683      }
 684
 685      fprintf(stderr, "%s: %s: %s",
 686         dp->filename != NULL ? dp->filename : "<stdin>", lp, dp->operation);
 687
 688      if (dp->transforms != 0)
 689      {
 690         int tr = dp->transforms;
 691
 692         if (is_combo(tr))
 693            fprintf(stderr, "(0x%x)", tr);
 694
 695         else
 696            fprintf(stderr, "(%s)", transform_name(tr));
 697      }
 698
 699      fprintf(stderr, ": ");
 700
 701      va_start(ap, fmt);
 702      vfprintf(stderr, fmt, ap);
 703      va_end(ap);
 704
 705      fputc('\n', stderr);
 706   }
 707   /* else do not output any message */
 708
 709   /* Errors cause this routine to exit to the fail code */
 710   if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
 711      longjmp(dp->error_return, level);
 712}
 713
 714/* error handler callbacks for libpng */
 715static void PNGCBAPI
 716display_warning(png_structp pp, png_const_charp warning)
 717{
 718   display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning);
 719}
 720
 721static void PNGCBAPI
 722display_error(png_structp pp, png_const_charp error)
 723{
 724   struct display *dp = get_dp(pp);
 725
 726   display_log(dp, LIBPNG_ERROR, "%s", error);
 727}
 728
 729static void
 730display_cache_file(struct display *dp, const char *filename)
 731   /* Does the initial cache of the file. */
 732{
 733   FILE *fp;
 734   int ret;
 735
 736   dp->filename = filename;
 737
 738   if (filename != NULL)
 739   {
 740      fp = fopen(filename, "rb");
 741      if (fp == NULL)
 742         display_log(dp, USER_ERROR, "open failed: %s", strerror(errno));
 743   }
 744
 745   else
 746      fp = stdin;
 747
 748   ret = buffer_from_file(&dp->original_file, fp);
 749
 750   fclose(fp);
 751
 752   if (ret != 0)
 753      display_log(dp, APP_ERROR, "read failed: %s", strerror(ret));
 754}
 755
 756static void
 757buffer_read(struct display *dp, struct buffer *bp, png_bytep data,
 758   png_size_t size)
 759{
 760   struct buffer_list *last = bp->current;
 761   size_t read_count = bp->read_count;
 762
 763   while (size > 0)
 764   {
 765      size_t avail;
 766
 767      if (last == NULL ||
 768         (last == bp->last && read_count >= bp->end_count))
 769      {
 770         display_log(dp, USER_ERROR, "file truncated (%lu bytes)",
 771            (unsigned long)size);
 772         /*NOTREACHED*/
 773         break;
 774      }
 775
 776      else if (read_count >= sizeof last->buffer)
 777      {
 778         /* Move to the next buffer: */
 779         last = last->next;
 780         read_count = 0;
 781         bp->current = last; /* Avoid update outside the loop */
 782
 783         /* And do a sanity check (the EOF case is caught above) */
 784         if (last == NULL)
 785         {
 786            display_log(dp, INTERNAL_ERROR, "damaged buffer list");
 787            /*NOTREACHED*/
 788            break;
 789         }
 790      }
 791
 792      avail = (sizeof last->buffer) - read_count;
 793      if (avail > size)
 794         avail = size;
 795
 796      memcpy(data, last->buffer + read_count, avail);
 797      read_count += avail;
 798      size -= avail;
 799      data += avail;
 800   }
 801
 802   bp->read_count = read_count;
 803}
 804
 805static void PNGCBAPI
 806read_function(png_structp pp, png_bytep data, png_size_t size)
 807{
 808   buffer_read(get_dp(pp), get_buffer(pp), data, size);
 809}
 810
 811static void
 812read_png(struct display *dp, struct buffer *bp, const char *operation,
 813   int transforms)
 814{
 815   png_structp pp;
 816   png_infop   ip;
 817
 818   /* This cleans out any previous read and sets operation and transforms to
 819    * empty.
 820    */
 821   display_clean_read(dp);
 822
 823   if (operation != NULL) /* else this is a verify and do not overwrite info */
 824   {
 825      dp->operation = operation;
 826      dp->transforms = transforms;
 827   }
 828
 829   dp->read_pp = pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp,
 830      display_error, display_warning);
 831   if (pp == NULL)
 832      display_log(dp, LIBPNG_ERROR, "failed to create read struct");
 833
 834   /* The png_read_png API requires us to make the info struct, but it does the
 835    * call to png_read_info.
 836    */
 837   dp->read_ip = ip = png_create_info_struct(pp);
 838   if (ip == NULL)
 839      display_log(dp, LIBPNG_ERROR, "failed to create info struct");
 840
 841#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
 842      /* Remove the user limits, if any */
 843      png_set_user_limits(pp, 0x7fffffff, 0x7fffffff);
 844#  endif
 845
 846   /* Set the IO handling */
 847   buffer_start_read(bp);
 848   png_set_read_fn(pp, bp, read_function);
 849
 850   png_read_png(pp, ip, transforms, NULL/*params*/);
 851
 852#if 0 /* crazy debugging */
 853   {
 854      png_bytep pr = png_get_rows(pp, ip)[0];
 855      size_t rb = png_get_rowbytes(pp, ip);
 856      size_t cb;
 857      char c = ' ';
 858
 859      fprintf(stderr, "%.4x %2d (%3lu bytes):", transforms, png_get_bit_depth(pp,ip), (unsigned long)rb);
 860
 861      for (cb=0; cb<rb; ++cb)
 862         fputc(c, stderr), fprintf(stderr, "%.2x", pr[cb]), c='.';
 863
 864      fputc('\n', stderr);
 865   }
 866#endif
 867}
 868
 869static void
 870update_display(struct display *dp)
 871   /* called once after the first read to update all the info, original_pp and
 872    * original_ip must have been filled in.
 873    */
 874{
 875   png_structp pp;
 876   png_infop   ip;
 877
 878   /* Now perform the initial read with a 0 tranform. */
 879   read_png(dp, &dp->original_file, "original read", 0/*no transform*/);
 880
 881   /* Move the result to the 'original' fields */
 882   dp->original_pp = pp = dp->read_pp, dp->read_pp = NULL;
 883   dp->original_ip = ip = dp->read_ip, dp->read_ip = NULL;
 884
 885   dp->original_rowbytes = png_get_rowbytes(pp, ip);
 886   if (dp->original_rowbytes == 0)
 887      display_log(dp, LIBPNG_BUG, "png_get_rowbytes returned 0");
 888
 889   dp->chunks = png_get_valid(pp, ip, 0xffffffff);
 890   if ((dp->chunks & PNG_INFO_IDAT) == 0) /* set by png_read_png */
 891      display_log(dp, LIBPNG_BUG, "png_read_png did not set IDAT flag");
 892
 893   dp->original_rows = png_get_rows(pp, ip);
 894   if (dp->original_rows == NULL)
 895      display_log(dp, LIBPNG_BUG, "png_read_png did not create row buffers");
 896
 897   if (!png_get_IHDR(pp, ip,
 898      &dp->width, &dp->height, &dp->bit_depth, &dp->color_type,
 899      &dp->interlace_method, &dp->compression_method, &dp->filter_method))
 900      display_log(dp, LIBPNG_BUG, "png_get_IHDR failed");
 901
 902   /* 'active' transforms are discovered based on the original image format;
 903    * running one active transform can activate others.  At present the code
 904    * does not attempt to determine the closure.
 905    */
 906   {
 907      png_uint_32 chunks = dp->chunks;
 908      int active = 0, inactive = 0;
 909      int ct = dp->color_type;
 910      int bd = dp->bit_depth;
 911      unsigned int i;
 912
 913      for (i=0; i<TTABLE_SIZE; ++i)
 914      {
 915         int transform = transform_info[i].transform;
 916
 917         if ((transform_info[i].valid_chunks == 0 ||
 918               (transform_info[i].valid_chunks & chunks) != 0) &&
 919            (transform_info[i].color_mask_required & ct) == 
 920               transform_info[i].color_mask_required &&
 921            (transform_info[i].color_mask_absent & ct) == 0 &&
 922            (transform_info[i].bit_depths & bd) != 0 &&
 923            (transform_info[i].when & TRANSFORM_R) != 0)
 924            active |= transform;
 925
 926         else if ((transform_info[i].when & TRANSFORM_R) != 0)
 927            inactive |= transform;
 928      }
 929
 930      /* Some transforms appear multiple times in the table; the 'active' status
 931       * is the logical OR of these and the inactive status must be adjusted to
 932       * take this into account.
 933       */
 934      inactive &= ~active;
 935
 936      dp->active_transforms = active;
 937      dp->ignored_transforms = inactive; /* excluding write-only transforms */
 938
 939      if (active == 0)
 940         display_log(dp, INTERNAL_ERROR, "bad transform table");
 941   }
 942}
 943
 944static int
 945compare_read(struct display *dp, int applied_transforms)
 946{
 947   /* Compare the png_info from read_ip with original_info */
 948   size_t rowbytes;
 949   png_uint_32 width, height;
 950   int bit_depth, color_type;
 951   int interlace_method, compression_method, filter_method;
 952   const char *e = NULL;
 953
 954   png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth,
 955      &color_type, &interlace_method, &compression_method, &filter_method);
 956
 957#  define C(item) if (item != dp->item) \
 958      display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\
 959         (unsigned long)dp->item, (unsigned long)item), e = #item
 960
 961   /* The IHDR should be identical: */
 962   C(width);
 963   C(height);
 964   C(bit_depth);
 965   C(color_type);
 966   C(interlace_method);
 967   C(compression_method);
 968   C(filter_method);
 969
 970   /* 'e' remains set to the name of the last thing changed: */
 971   if (e)
 972      display_log(dp, APP_ERROR, "IHDR changed (%s)", e);
 973
 974   /* All the chunks from the original PNG should be preserved in the output PNG
 975    * because the PNG format has not been changed.
 976    */
 977   {
 978      unsigned long chunks =
 979         png_get_valid(dp->read_pp, dp->read_ip, 0xffffffff);
 980      
 981      if (chunks != dp->chunks)
 982         display_log(dp, APP_FAIL, "PNG chunks changed from 0x%lx to 0x%lx",
 983            (unsigned long)dp->chunks, chunks);
 984   }
 985
 986   /* rowbytes should be the same */
 987   rowbytes = png_get_rowbytes(dp->read_pp, dp->read_ip);
 988
 989   /* NOTE: on 64-bit systems this may trash the top bits of rowbytes,
 990    * which could lead to weird error messages.
 991    */
 992   if (rowbytes != dp->original_rowbytes)
 993      display_log(dp, APP_ERROR, "PNG rowbytes changed from %lu to %lu",
 994         (unsigned long)dp->original_rowbytes, (unsigned long)rowbytes);
 995
 996   /* The rows should be the same too, unless the applied transforms includes
 997    * the shift transform, in which case low bits may have been lost.
 998    */
 999   {
1000      png_bytepp rows = png_get_rows(dp->read_pp, dp->read_ip);
1001      unsigned int mask;  /* mask (if not zero) for the final byte */
1002
1003      if (bit_depth < 8)
1004      {
1005         /* Need the stray bits at the end, this depends only on the low bits
1006          * of the image width; overflow does not matter.  If the width is an
1007          * exact multiple of 8 bits this gives a mask of 0, not 0xff.
1008          */
1009         mask = 0xff & (0xff00 >> ((bit_depth * width) & 7));
1010      }
1011
1012      else
1013         mask = 0;
1014
1015      if (rows == NULL)
1016         display_log(dp, LIBPNG_BUG, "png_get_rows returned NULL");
1017
1018      if ((applied_transforms & PNG_TRANSFORM_SHIFT) == 0 ||
1019         (dp->active_transforms & PNG_TRANSFORM_SHIFT) == 0 ||
1020         color_type == PNG_COLOR_TYPE_PALETTE)
1021      {
1022         unsigned long y;
1023
1024         for (y=0; y<height; ++y)
1025         {
1026            png_bytep row = rows[y];
1027            png_bytep orig = dp->original_rows[y];
1028
1029            if (memcmp(row, orig, rowbytes-(mask != 0)) != 0 || (mask != 0 &&
1030               ((row[rowbytes-1] & mask) != (orig[rowbytes-1] & mask))))
1031            {
1032               size_t x;
1033
1034               /* Find the first error */
1035               for (x=0; x<rowbytes-1; ++x) if (row[x] != orig[x])
1036                  break;
1037
1038               display_log(dp, APP_FAIL,
1039                  "byte(%lu,%lu) changed 0x%.2x -> 0x%.2x",
1040                  (unsigned long)x, (unsigned long)y, orig[x], row[x]);
1041               return 0; /* don't keep reporting failed rows on 'continue' */
1042            }
1043         }
1044      }
1045
1046      else
1047      {
1048         unsigned long y;
1049         int bpp;   /* bits-per-pixel then bytes-per-pixel */
1050         /* components are up to 8 bytes in size */
1051         png_byte sig_bits[8];
1052         png_color_8p sBIT;
1053
1054         if (png_get_sBIT(dp->read_pp, dp->read_ip, &sBIT) != PNG_INFO_sBIT)
1055            display_log(dp, INTERNAL_ERROR,
1056               "active shift transform but no sBIT in file");
1057
1058         switch (color_type)
1059         {
1060            case PNG_COLOR_TYPE_GRAY:
1061               sig_bits[0] = sBIT->gray;
1062               bpp = bit_depth;
1063               break;
1064
1065            case PNG_COLOR_TYPE_GA:
1066               sig_bits[0] = sBIT->gray;
1067               sig_bits[1] = sBIT->alpha;
1068               bpp = 2 * bit_depth;
1069               break;
1070
1071            case PNG_COLOR_TYPE_RGB:
1072               sig_bits[0] = sBIT->red;
1073               sig_bits[1] = sBIT->green;
1074               sig_bits[2] = sBIT->blue;
1075               bpp = 3 * bit_depth;
1076               break;
1077
1078            case PNG_COLOR_TYPE_RGBA:
1079               sig_bits[0] = sBIT->red;
1080               sig_bits[1] = sBIT->green;
1081               sig_bits[2] = sBIT->blue;
1082               sig_bits[3] = sBIT->alpha;
1083               bpp = 4 * bit_depth;
1084               break;
1085
1086            default:
1087               display_log(dp, LIBPNG_ERROR, "invalid colour type %d",
1088                  color_type);
1089               /*NOTREACHED*/
1090               bpp = 0;
1091               break;
1092         }
1093
1094         {
1095            int b;
1096
1097            for (b=0; 8*b<bpp; ++b)
1098            {
1099               /* libpng should catch this; if not there is a security issue
1100                * because an app (like this one) may overflow an array. In fact
1101                * libpng doesn't catch this at present.
1102                */
1103               if (sig_bits[b] == 0 || sig_bits[b] > bit_depth/*!palette*/)
1104                  display_log(dp, LIBPNG_BUG,
1105                     "invalid sBIT[%u]  value %d returned for PNG bit depth %d",
1106                     b, sig_bits[b], bit_depth);
1107            }
1108         }
1109
1110         if (bpp < 8 && bpp != bit_depth)
1111         {
1112            /* sanity check; this is a grayscale PNG; something is wrong in the
1113             * code above.
1114             */
1115            display_log(dp, INTERNAL_ERROR, "invalid bpp %u for bit_depth %u",
1116               bpp, bit_depth);
1117         }
1118
1119         switch (bit_depth)
1120         {
1121            int b;
1122
1123            case 16: /* Two bytes per component, bit-endian */
1124               for (b = (bpp >> 4); b > 0; )
1125               {
1126                  unsigned int sig = (unsigned int)(0xffff0000 >> sig_bits[b]);
1127
1128                  sig_bits[2*b+1] = (png_byte)sig;
1129                  sig_bits[2*b+0] = (png_byte)(sig >> 8); /* big-endian */
1130               }
1131               break;
1132
1133            case 8: /* One byte per component */
1134               for (b=0; b*8 < bpp; ++b)
1135                  sig_bits[b] = (png_byte)(0xff00 >> sig_bits[b]);
1136               break;
1137
1138            case 1: /* allowed, but dumb */
1139               /* Value is 1 */
1140               sig_bits[0] = 0xff;
1141               break;
1142
1143            case 2: /* Replicate 4 times */
1144               /* Value is 1 or 2 */
1145               b = 0x3 & ((0x3<<2) >> sig_bits[0]);
1146               b |= b << 2;
1147               b |= b << 4;
1148               sig_bits[0] = (png_byte)b;
1149               break;
1150
1151            case 4: /* Relicate twice */
1152               /* Value is 1, 2, 3 or 4 */
1153               b = 0xf & ((0xf << 4) >> sig_bits[0]);
1154               b |= b << 4;
1155               sig_bits[0] = (png_byte)b;
1156               break;
1157
1158            default:
1159               display_log(dp, LIBPNG_BUG, "invalid bit depth %d", bit_depth);
1160               break;
1161         }
1162
1163         /* Convert bpp to bytes; this gives '1' for low-bit depth grayscale,
1164          * where there are multiple pixels per byte.
1165          */
1166         bpp = (bpp+7) >> 3;
1167
1168         /* The mask can be combined with sig_bits[0] */
1169         if (mask != 0)
1170         {
1171            mask &= sig_bits[0];
1172
1173            if (bpp != 1 || mask == 0)
1174               display_log(dp, INTERNAL_ERROR, "mask calculation error %u, %u",
1175                  bpp, mask);
1176         }
1177
1178         for (y=0; y<height; ++y)
1179         {
1180            png_bytep row = rows[y];
1181            png_bytep orig = dp->original_rows[y];
1182            unsigned long x;
1183
1184            for (x=0; x<(width-(mask!=0)); ++x)
1185            {
1186               int b;
1187
1188               for (b=0; b<bpp; ++b)
1189               {
1190                  if ((*row++ & sig_bits[b]) != (*orig++ & sig_bits[b]))
1191                  {
1192                     display_log(dp, APP_FAIL,
1193                        "significant bits at (%lu[%u],%lu) changed %.2x->%.2x",
1194                        x, b, y, orig[-1], row[-1]);
1195                     return 0;
1196                  }
1197               }
1198            }
1199
1200            if (mask != 0 && (*row & mask) != (*orig & mask))
1201            {
1202               display_log(dp, APP_FAIL,
1203                  "significant bits at (%lu[end],%lu) changed", x, y);
1204               return 0;
1205            }
1206         } /* for y */
1207      }
1208   }
1209
1210   return 1; /* compare succeeded */
1211}
1212
1213#ifdef PNG_WRITE_SUPPORTED
1214static void
1215buffer_write(struct display *dp, struct buffer *buffer, png_bytep data,
1216   png_size_t size)
1217   /* Generic write function used both from the write callback provided to
1218    * libpng and from the generic read code.
1219    */
1220{
1221   /* Write the data into the buffer, adding buffers as required */
1222   struct buffer_list *last = buffer->last;
1223   size_t end_count = buffer->end_count;
1224
1225   while (size > 0)
1226   {
1227      size_t avail;
1228
1229      if (end_count >= sizeof last->buffer)
1230      {
1231         if (last->next == NULL)
1232         {
1233            last = buffer_extend(last);
1234
1235            if (last == NULL)
1236               display_log(dp, APP_ERROR, "out of memory saving file");
1237         }
1238
1239         else
1240            last = last->next;
1241
1242         buffer->last = last; /* avoid the need to rewrite every time */
1243         end_count = 0;
1244      }
1245
1246      avail = (sizeof last->buffer) - end_count;
1247      if (avail > size)
1248         avail = size;
1249
1250      memcpy(last->buffer + end_count, data, avail);
1251      end_count += avail;
1252      size -= avail;
1253      data += avail;
1254   }
1255
1256   buffer->end_count = end_count;
1257}
1258
1259static void PNGCBAPI
1260write_function(png_structp pp, png_bytep data, png_size_t size)
1261{
1262   buffer_write(get_dp(pp), get_buffer(pp), data, size);
1263}
1264
1265static void
1266write_png(struct display *dp, png_infop ip, int transforms)
1267{
1268   display_clean_write(dp); /* safety */
1269
1270   buffer_start_write(&dp->written_file);
1271   dp->operation = "write";
1272   dp->transforms = transforms;
1273
1274   dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp,
1275      display_error, display_warning);
1276
1277   if (dp->write_pp == NULL)
1278      display_log(dp, APP_ERROR, "failed to create write png_struct");
1279
1280   png_set_write_fn(dp->write_pp, &dp->written_file, write_function,
1281      NULL/*flush*/);
1282
1283#  ifdef PNG_SET_USER_LIMITS_SUPPORTED
1284      /* Remove the user limits, if any */
1285      png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff);
1286#  endif
1287
1288   /* Certain transforms require the png_info to be zapped to allow the
1289    * transform to work correctly.
1290    */
1291   if (transforms & (PNG_TRANSFORM_PACKING|
1292                     PNG_TRANSFORM_STRIP_FILLER|
1293                     PNG_TRANSFORM_STRIP_FILLER_BEFORE))
1294   {
1295      int ct = dp->color_type;
1296
1297      if (transforms & (PNG_TRANSFORM_STRIP_FILLER|
1298                        PNG_TRANSFORM_STRIP_FILLER_BEFORE))
1299         ct &= ~PNG_COLOR_MASK_ALPHA;
1300
1301      png_set_IHDR(dp->write_pp, ip, dp->width, dp->height, dp->bit_depth, ct,
1302         dp->interlace_method, dp->compression_method, dp->filter_method);
1303   }
1304
1305   png_write_png(dp->write_pp, ip, transforms, NULL/*params*/);
1306
1307   /* Clean it on the way out - if control returns to the caller then the
1308    * written_file contains the required data.
1309    */
1310   display_clean_write(dp);
1311}
1312#endif /* WRITE_SUPPORTED */
1313
1314static int
1315skip_transform(struct display *dp, int tr)
1316   /* Helper to test for a bad combo and log it if it is skipped */
1317{
1318   if ((dp->options & SKIP_BUGS) != 0 && is_bad_combo(tr))
1319   {
1320      /* Log this to stdout if logging is on, otherwise just do an information
1321       * display_log.
1322       */
1323      if ((dp->options & LOG_SKIPPED) != 0)
1324      {
1325         printf("SKIP: %s transforms ", dp->filename);
1326
1327         while (tr != 0)
1328         {
1329            int next = first_transform(tr);
1330            tr &= ~next;
1331
1332            printf("%s", transform_name(next));
1333            if (tr != 0)
1334               putchar('+');
1335         }
1336
1337         putchar('\n');
1338      }
1339
1340      else
1341         display_log(dp, INFORMATION, "%s: skipped known bad combo 0x%x",
1342            dp->filename, tr);
1343
1344      return 1; /* skip */
1345   }
1346
1347   return 0; /* don't skip */
1348}
1349
1350static void
1351test_one_file(struct display *dp, const char *filename)
1352{
1353   /* First cache the file and update the display original file
1354    * information for the new file.
1355    */
1356   dp->operation = "cache file";
1357   dp->transforms = 0;
1358   display_cache_file(dp, filename);
1359   update_display(dp);
1360
1361   /* First test: if there are options that should be ignored for this file
1362    * verify that they really are ignored.
1363    */
1364   if (dp->ignored_transforms != 0)
1365   {
1366      read_png(dp, &dp->original_file, "ignored transforms",
1367         dp->ignored_transforms);
1368
1369      /* The result should be identical to the original_rows */
1370      if (!compare_read(dp, 0/*transforms applied*/))
1371         return; /* no point testing more */
1372   }
1373
1374#ifdef PNG_WRITE_SUPPORTED
1375   /* Second test: write the original PNG data out to a new file (to test the
1376    * write side) then read the result back in and make sure that it hasn't
1377    * changed.
1378    */
1379   dp->operation = "write";
1380   write_png(dp, dp->original_ip, 0/*transforms*/);
1381   read_png(dp, &dp->written_file, NULL, 0/*transforms*/);
1382   if (!compare_read(dp, 0/*transforms applied*/))
1383      return;
1384#endif
1385
1386   /* Third test: the active options.  Test each in turn, or, with the
1387    * EXHAUSTIVE option, test all possible combinations.
1388    */
1389   {
1390      /* Use unsigned int here because the code below to increment through all
1391       * the possibilities exhaustively has to use a compare and that must be
1392       * unsigned, because some transforms are negative on a 16-bit system.
1393       */
1394      unsigned int active = dp->active_transforms;
1395      const int exhaustive = (dp->options & EXHAUSTIVE) != 0;
1396      unsigned int current = first_transform(active);
1397      unsigned int bad_transforms = 0;
1398      unsigned int bad_combo = ~0U;    /* bitwise AND of failing transforms */
1399      unsigned int bad_combo_list = 0; /* bitwise OR of failures */
1400
1401      for (;;)
1402      {
1403         read_png(dp, &dp->original_file, "active transforms", current);
1404
1405         /* If this involved any irreversible transformations then if we write
1406          * it out with just the reversible transformations and read it in again
1407          * with the same transforms we should get the same thing.  At present
1408          * this isn't done - it just seems like a waste of time and it would
1409          * require two sets of read png_struct/png_info.
1410          *
1411          * If there were no irreversible transformations then if we write it
1412          * out and read it back in again (without the reversible transforms)
1413          * we should get back to the place where we started.
1414          */
1415#ifdef PNG_WRITE_SUPPORTED
1416         if ((current & write_transforms) == current)
1417         {
1418            /* All transforms reversible: write the PNG with the transformations
1419             * reversed, then read it back in with no transformations.  The
1420             * result should be the same as the original apart from the loss of
1421             * low order bits because of the SHIFT/sBIT transform.
1422             */
1423            dp->operation = "reversible transforms";
1424            write_png(dp, dp->read_ip, current);
1425
1426            /* And if this is read back in, because all the transformations were
1427             * reversible, the result should be the same.
1428             */
1429            read_png(dp, &dp->written_file, NULL, 0);
1430            if (!compare_read(dp, current/*for the SHIFT/sBIT transform*/))
1431            {
1432               /* This set of transforms failed.  If a single bit is set - if
1433                * there is just one transform - don't include this in further
1434                * 'exhaustive' tests.  Notice that each transform is tested on
1435                * its own before testing combos in the exhaustive case.
1436                */
1437               if (is_combo(current))
1438               {
1439                  bad_combo &= current;
1440                  bad_combo_list |= current;
1441               }
1442
1443               else
1444                  bad_transforms |= current;
1445            }
1446         }
1447#endif
1448
1449         /* Now move to the next transform */
1450         if (exhaustive) /* all combinations */
1451         {
1452            unsigned int next = current;
1453
1454            do
1455            {
1456               if (next == read_transforms) /* Everything tested */
1457                  goto combo;
1458
1459               ++next;
1460            }  /* skip known bad combos if the relevant option is set; skip
1461                * combos involving known bad single transforms in all cases.
1462                */
1463            while (  (next & read_transforms) <= current
1464                  || (next & active) == 0 /* skip cases that do nothing */
1465                  || (next & bad_transforms) != 0
1466                  || skip_transform(dp, next));
1467
1468            assert((next & read_transforms) == next);
1469            current = next;
1470         }
1471
1472         else /* one at a time */
1473         {
1474            active &= ~current;
1475
1476            if (active == 0)
1477               goto combo;
1478
1479            current = first_transform(active);
1480         }
1481      }
1482
1483combo:
1484      if (dp->options & FIND_BAD_COMBOS)
1485      {
1486         /* bad_combos identifies the combos that occur in all failing cases;
1487          * bad_combo_list identifies transforms that do not prevent the
1488          * failure.
1489          */
1490         if (bad_combo != ~0U)
1491            printf("%s[0x%x]: PROBLEM: 0x%x[0x%x] ANTIDOTE: 0x%x\n",
1492               dp->filename, active, bad_combo, bad_combo_list,
1493               rw_transforms & ~bad_combo_list);
1494
1495         else
1496            printf("%s: no %sbad combos found\n", dp->filename,
1497               (dp->options & SKIP_BUGS) ? "additional " : "");
1498      }
1499   }
1500}
1501
1502static int
1503do_test(struct display *dp, const char *file)
1504   /* Exists solely to isolate the setjmp clobbers */
1505{
1506   int ret = setjmp(dp->error_return);
1507
1508   if (ret == 0)
1509   {
1510      test_one_file(dp, file);
1511      return 0;
1512   }
1513
1514   else if (ret < ERRORS) /* shouldn't longjmp on warnings */
1515      display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
1516
1517   return ret;
1518}
1519
1520int
1521main(const int argc, const char * const * const argv)
1522{
1523   /* For each file on the command line test it with a range of transforms */
1524   int option_end, ilog = 0;
1525   struct display d;
1526
1527   validate_T();
1528   display_init(&d);
1529
1530   for (option_end=1; option_end<argc; ++option_end)
1531   {
1532      const char *name = argv[option_end];
1533
1534      if (strcmp(name, "--verbose") == 0)
1535         d.options = (d.options & ~LEVEL_MASK) | VERBOSE;
1536
1537      else if (strcmp(name, "--warnings") == 0)
1538         d.options = (d.options & ~LEVEL_MASK) | WARNINGS;
1539
1540      else if (strcmp(name, "--errors") == 0)
1541         d.options = (d.options & ~LEVEL_MASK) | ERRORS;
1542
1543      else if (strcmp(name, "--quiet") == 0)
1544         d.options = (d.options & ~LEVEL_MASK) | QUIET;
1545
1546      else if (strcmp(name, "--exhaustive") == 0)
1547         d.options |= EXHAUSTIVE;
1548
1549      else if (strcmp(name, "--fast") == 0)
1550         d.options &= ~EXHAUSTIVE;
1551
1552      else if (strcmp(name, "--strict") == 0)
1553         d.options |= STRICT;
1554
1555      else if (strcmp(name, "--relaxed") == 0)
1556         d.options &= ~STRICT;
1557
1558      else if (strcmp(name, "--log") == 0)
1559      {
1560         ilog = option_end; /* prevent display */
1561         d.options |= LOG;
1562      }
1563
1564      else if (strcmp(name, "--nolog") == 0)
1565         d.options &= ~LOG;
1566
1567      else if (strcmp(name, "--continue") == 0)
1568         d.options |= CONTINUE;
1569
1570      else if (strcmp(name, "--stop") == 0)
1571         d.options &= ~CONTINUE;
1572
1573      else if (strcmp(name, "--skip-bugs") == 0)
1574         d.options |= SKIP_BUGS;
1575
1576      else if (strcmp(name, "--test-all") == 0)
1577         d.options &= ~SKIP_BUGS;
1578
1579      else if (strcmp(name, "--log-skipped") == 0)
1580         d.options |= LOG_SKIPPED;
1581
1582      else if (strcmp(name, "--nolog-skipped") == 0)
1583         d.options &= ~LOG_SKIPPED;
1584
1585      else if (strcmp(name, "--find-bad-combos") == 0)
1586         d.options |= FIND_BAD_COMBOS;
1587
1588      else if (strcmp(name, "--nofind-bad-combos") == 0)
1589         d.options &= ~FIND_BAD_COMBOS;
1590
1591      else if (name[0] == '-' && name[1] == '-')
1592      {
1593         fprintf(stderr, "pngimage: %s: unknown option\n", name);
1594         return 99;
1595      }
1596
1597      else
1598         break; /* Not an option */
1599   }
1600
1601   {
1602      int i;
1603      int errors = 0;
1604
1605      for (i=option_end; i<argc; ++i)
1606      {
1607         {
1608            int ret = do_test(&d, argv[i]);
1609
1610            if (ret > QUIET) /* abort on user or internal error */
1611               return 99;
1612         }
1613
1614         /* Here on any return, including failures, except user/internal issues
1615          */
1616         {
1617            const int pass = (d.options & STRICT) ?
1618               RESULT_STRICT(d.results) : RESULT_RELAXED(d.results);
1619
1620            if (!pass)
1621               ++errors;
1622
1623            if (d.options & LOG)
1624            {
1625               int j;
1626
1627               printf("%s: pngimage ", pass ? "PASS" : "FAIL");
1628
1629               for (j=1; j<option_end; ++j) if (j != ilog)
1630                  printf("%s ", argv[j]);
1631
1632               printf("%s\n", d.filename);
1633            }
1634         }
1635
1636         display_clean(&d);
1637      }
1638
1639      /* Release allocated memory */
1640      display_destroy(&d);
1641
1642      return errors != 0;
1643   }
1644}
1645#else /* !PNG_INFO_IMAGE_SUPPORTED || !PNG_READ_SUPPORTED */
1646int
1647main(void)
1648{
1649   fprintf(stderr, "pngimage: no support for png_read/write_image\n");
1650   return 77;
1651}
1652#endif