pngtest.c 55.1 KB
Newer Older
A
Andreas Dilger 已提交
1

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * Last changed in libpng 1.6.1 [March 28, 2013]
5
 * Copyright (c) 1998-2013 Glenn Randers-Pehrson
6 7
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8
 *
9
 * This code is released under the libpng license.
10
 * For conditions of distribution and use, see the disclaimer
11
 * and license in png.h
12
 *
13 14 15 16 17 18
 * This program reads in a PNG image, writes it out again, and then
 * compares the two files.  If the files are identical, this shows that
 * the basic chunk handling, filtering, and (de)compression code is working
 * properly.  It does not currently test all of the transforms, although
 * it probably should.
 *
19
 * The program will report "FAIL" in certain legitimate cases:
20
 * 1) when the compression level or filter selection method is changed.
21
 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
22 23
 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
 *    exist in the input file.
24 25
 * 4) others not listed here...
 * In these cases, it is best to check with another tool such as "pngcheck"
26
 * to see what the differences between the two files are.
27 28 29
 *
 * If a filename is given on the command-line, then this file is used
 * for the input, rather than the default "pngtest.png".  This allows
30 31
 * testing a wide variety of files easily.  You can also test a number
 * of files at once by typing "pngtest -m file1.png file2.png ..."
32
 */
G
Guy Schalnat 已提交
33

34 35
#define _POSIX_SOURCE 1

36 37 38 39 40 41 42 43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Defined so I can write to a file on gui/windowing platforms */
/*  #define STDERR stderr  */
#define STDERR stdout   /* For DOS */

44
#include "png.h"
45 46 47

#ifdef PNG_READ_SUPPORTED /* else nothing can be done */
#include "zlib.h"
48 49 50 51
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
52
#define FCLOSE(file) fclose(file)
53

54
#ifndef PNG_STDIO_SUPPORTED
55
typedef FILE                * png_FILE_p;
56 57
#endif

58
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
59
#ifndef PNG_DEBUG
60 61 62
#  define PNG_DEBUG 0
#endif

63 64 65 66 67 68 69 70 71
#if PNG_DEBUG > 1
#  define pngtest_debug(m)        ((void)fprintf(stderr, m "\n"))
#  define pngtest_debug1(m,p1)    ((void)fprintf(stderr, m "\n", p1))
#  define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2))
#else
#  define pngtest_debug(m)        ((void)0)
#  define pngtest_debug1(m,p1)    ((void)0)
#  define pngtest_debug2(m,p1,p2) ((void)0)
#endif
72

73
#if !PNG_DEBUG
74
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
75
#endif
A
Andreas Dilger 已提交
76

77 78 79 80
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

81
#ifndef PNG_FLOATING_POINT_SUPPORTED
82 83 84
#undef PNGTEST_TIMING
#endif

85 86 87 88 89
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

90
#ifdef PNG_TIME_RFC1123_SUPPORTED
91
#define PNG_tIME_STRING_LENGTH 29
92
static int tIME_chunk_present = 0;
93
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
94 95
#endif

96
static int verbose = 0;
97
static int strict = 0;
98 99 100 101
static int relaxed = 0;
static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */
102

G
Guy Schalnat 已提交
103 104 105 106
#ifdef __TURBOC__
#include <mem.h>
#endif

107 108 109 110 111
/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
#ifndef png_jmpbuf
#  define png_jmpbuf(png_ptr) png_ptr->jmpbuf
#endif

112 113 114 115 116 117 118 119 120 121 122
/* Defines for unknown chunk handling if required. */
#ifndef PNG_HANDLE_CHUNK_ALWAYS
#  define PNG_HANDLE_CHUNK_ALWAYS       3
#endif
#ifndef PNG_HANDLE_CHUNK_IF_SAFE
#  define PNG_HANDLE_CHUNK_IF_SAFE      2
#endif

/* Utility to save typing/errors, the argument must be a name */
#define MEMZERO(var) ((void)memset(&var, 0, sizeof var))

123
/* Example of using row callbacks to make a simple progress meter */
124 125 126
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
127

128
static void PNGCBAPI
129
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
130
{
131 132
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
133

134 135 136 137 138 139
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
140

141
   status_dots--;
142

143 144 145 146 147
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
148

149
   fprintf(stdout, "r");
150
}
151

152 153
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
154
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
155
{
156 157
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
158

159
   fprintf(stdout, "w");
160
}
161
#endif
162 163


164
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
165
/* Example of using user transform callback (we don't transform anything,
166 167 168
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
169
static png_uint_32 filters_used[256];
170
static void PNGCBAPI
171 172
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
173
   if (png_ptr != NULL && row_info != NULL)
174
      ++filters_used[*(data - 1)];
175 176 177
}
#endif

178
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
179
/* Example of using user transform callback (we don't transform anything,
180 181
 * but merely count the zero samples)
 */
182

183
static png_uint_32 zero_samples;
184

185
static void PNGCBAPI
186
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
187 188
{
   png_bytep dp = data;
189 190
   if (png_ptr == NULL)
      return;
191

192
   /* Contents of row_info:
193 194 195 196 197 198 199 200
    *  png_uint_32 width      width of row
    *  png_uint_32 rowbytes   number of bytes in row
    *  png_byte color_type    color type of pixels
    *  png_byte bit_depth     bit depth of samples
    *  png_byte channels      number of channels (1-4)
    *  png_byte pixel_depth   bits per pixel (depth*channels)
    */

201
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
202

203
    if (row_info->color_type == 0 || row_info->color_type == 3)
204
    {
205
       int pos = 0;
206
       png_uint_32 n, nstop;
207

208
       for (n = 0, nstop=row_info->width; n<nstop; n++)
209
       {
210
          if (row_info->bit_depth == 1)
211
          {
212 213
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
214

215
             if (pos == 8)
216
             {
217
                pos = 0;
218 219
                dp++;
             }
220
          }
221

222
          if (row_info->bit_depth == 2)
223
          {
224 225
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
226

227
             if (pos == 8)
228
             {
229
                pos = 0;
230 231
                dp++;
             }
232
          }
233

234
          if (row_info->bit_depth == 4)
235
          {
236 237
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
238

239
             if (pos == 8)
240
             {
241
                pos = 0;
242 243
                dp++;
             }
244
          }
245

246
          if (row_info->bit_depth == 8)
247 248
             if (*dp++ == 0)
                zero_samples++;
249

250
          if (row_info->bit_depth == 16)
251
          {
252 253
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
254 255 256 257
             dp+=2;
          }
       }
    }
258
    else /* Other color types */
259
    {
260
       png_uint_32 n, nstop;
261 262
       int channel;
       int color_channels = row_info->channels;
263
       if (row_info->color_type > 3)color_channels--;
264

265
       for (n = 0, nstop=row_info->width; n<nstop; n++)
266 267 268
       {
          for (channel = 0; channel < color_channels; channel++)
          {
269
             if (row_info->bit_depth == 8)
270 271
                if (*dp++ == 0)
                   zero_samples++;
272

273
             if (row_info->bit_depth == 16)
274
             {
275 276
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
277

278 279 280
                dp+=2;
             }
          }
281
          if (row_info->color_type > 3)
282 283
          {
             dp++;
284 285
             if (row_info->bit_depth == 16)
                dp++;
286 287 288 289
          }
       }
    }
}
290
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
291

292
#ifndef PNG_STDIO_SUPPORTED
293
/* START of code to validate stdio-free compilation */
294 295 296 297 298 299 300
/* These copies of the default read/write functions come from pngrio.c and
 * pngwio.c.  They allow "don't include stdio" testing of the library.
 * This is the function that does the actual reading of data.  If you are
 * not reading from a standard C stream, you should create a replacement
 * read_data function and use it at run time with png_set_read_fn(), rather
 * than changing the library.
 */
301

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op)
{
   png_uint_32 io_state = png_get_io_state(png_ptr);
   int err = 0;

   /* Check if the current operation (reading / writing) is as expected. */
   if ((io_state & PNG_IO_MASK_OP) != io_op)
      png_error(png_ptr, "Incorrect operation in I/O state");

   /* Check if the buffer size specific to the current location
    * (file signature / header / data / crc) is as expected.
    */
   switch (io_state & PNG_IO_MASK_LOC)
   {
   case PNG_IO_SIGNATURE:
      if (data_length > 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_HDR:
      if (data_length != 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_DATA:
      break;  /* no restrictions here */
   case PNG_IO_CHUNK_CRC:
      if (data_length != 4)
         err = 1;
      break;
   default:
      err = 1;  /* uninitialized */
   }
   if (err)
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

344
static void PNGCBAPI
345
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
346
{
347 348
   png_size_t check = 0;
   png_voidp io_ptr;
349 350 351 352

   /* fread() returns 0 on error, so it is OK to store this in a png_size_t
    * instead of an int, which is what fread() actually returns.
    */
353 354 355 356 357
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
358

359 360
   if (check != length)
   {
361
      png_error(png_ptr, "Read Error");
362
   }
363 364 365 366

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
367
}
G
Guy Schalnat 已提交
368

369
#ifdef PNG_WRITE_FLUSH_SUPPORTED
370
static void PNGCBAPI
371
pngtest_flush(png_structp png_ptr)
372
{
373
   /* Do nothing; fflush() is said to be just a waste of energy. */
374
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
375 376
}
#endif
G
Guy Schalnat 已提交
377

378
/* This is the function that does the actual writing of data.  If you are
379 380 381 382
 * not writing to a standard C stream, you should create a replacement
 * write_data function and use it at run time with png_set_write_fn(), rather
 * than changing the library.
 */
383
static void PNGCBAPI
384
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
385
{
386
   png_size_t check;
387

388
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
389

390 391 392 393
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
394 395 396 397

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
398
}
399
#endif /* !PNG_STDIO_SUPPORTED */
400 401 402 403 404 405

/* This function is called when there is a warning, but the library thinks
 * it can continue anyway.  Replacement functions don't have to do anything
 * here if you don't want to.  In the default configuration, png_ptr is
 * not used, but it is passed in case it may be useful.
 */
406 407 408 409 410
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

411
static void PNGCBAPI
412
pngtest_warning(png_structp png_ptr, png_const_charp message)
413 414
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
415 416
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
417

418
   ++warning_count;
419

420 421 422 423
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
424 425 426 427 428 429 430
}

/* This is the default error handling function.  Note that replacements for
 * this function MUST NOT RETURN, or the program will likely crash.  This
 * function is used by default, or if the program supplies NULL for the
 * error function pointer in png_set_error_fn().
 */
431
static void PNGCBAPI
432
pngtest_error(png_structp png_ptr, png_const_charp message)
433
{
434 435
   ++error_count;

436
   pngtest_warning(png_ptr, message);
437
   /* We can return because png_error calls the default handler, which is
438 439
    * actually OK in this case.
    */
440
}
441

442 443
/* END of code to validate stdio-free compilation */

444
/* START of code to validate memory allocation and deallocation */
445
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
446 447

/* Allocate memory.  For reasonable files, size should never exceed
448 449 450 451 452 453 454 455
 * 64K.  However, zlib may allocate more then 64K if you don't tell
 * it not to.  See zconf.h and png.h for more information.  zlib does
 * need to allocate exactly 64K, so whatever you call here must
 * have the ability to do that.
 *
 * This piece of code can be compiled to validate max 64K allocations
 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
 */
456 457
typedef struct memory_information
{
458
   png_alloc_size_t          size;
459
   png_voidp                 pointer;
460
   struct memory_information *next;
461
} memory_information;
462
typedef memory_information *memory_infop;
463 464 465 466

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
467 468
static int total_allocation = 0;
static int num_allocations = 0;
469

470 471 472
png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr,
    png_alloc_size_t size));
void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
473 474

png_voidp
475
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
476
{
477

478
   /* png_malloc has already tested for NULL; png_create_struct calls
479 480
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
481

482
   if (size == 0)
483
      return (NULL);
484 485 486 487

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
488
      /* Disable malloc_fn and free_fn */
489
      memory_infop pinfo;
490
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
491
      pinfo = (memory_infop)png_malloc(png_ptr,
492
         (sizeof *pinfo));
493 494
      pinfo->size = size;
      current_allocation += size;
495 496
      total_allocation += size;
      num_allocations ++;
497

498 499
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
500

501
      pinfo->pointer = png_malloc(png_ptr, size);
502
      /* Restore malloc_fn and free_fn */
503

504 505
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
506

507 508 509 510
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
511
         png_error(png_ptr,
512
           "out of memory in pngtest->png_debug_malloc");
513
      }
514

515 516 517
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
518
      memset(pinfo->pointer, 0xdd, pinfo->size);
519

520
      if (verbose)
521
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
522
            pinfo->pointer);
523

524
      return (png_voidp)(pinfo->pointer);
525 526 527 528
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
529
void PNGCBAPI
530
png_debug_free(png_structp png_ptr, png_voidp ptr)
531 532
{
   if (png_ptr == NULL)
533
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
534

535 536
   if (ptr == 0)
   {
537 538 539 540 541 542 543 544
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
545
      memory_infop *ppinfo = &pinformation;
546

547 548
      for (;;)
      {
549
         memory_infop pinfo = *ppinfo;
550

551 552
         if (pinfo->pointer == ptr)
         {
553 554 555 556 557
            *ppinfo = pinfo->next;
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
558
               the memory that is to be freed. */
559
            memset(ptr, 0x55, pinfo->size);
560
            png_free_default(png_ptr, pinfo);
561
            pinfo = NULL;
562 563
            break;
         }
564

565 566
         if (pinfo->next == NULL)
         {
567
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
568 569
            break;
         }
570

571 572 573 574 575
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
576
   if (verbose)
577
      printf("Freeing %p\n", ptr);
578

579
   png_free_default(png_ptr, ptr);
580
   ptr = NULL;
581
}
582
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
583 584
/* END of code to test memory allocation/deallocation */

585

586
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
587 588
/* Demonstration of user chunk support of the sTER and vpAg chunks */

589
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
590 591
chunk used in ImageMagick to store "virtual page" size).  */

592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
static struct user_chunk_data
{
   png_const_infop info_ptr;
   png_uint_32     vpAg_width, vpAg_height;
   png_byte        vpAg_units;
   png_byte        sTER_mode;
   int             location[2];
}
user_chunk_data;

/* Used for location and order; zero means nothing. */
#define have_sTER   0x01
#define have_vpAg   0x02
#define before_PLTE 0x10
#define before_IDAT 0x20
#define after_IDAT  0x40
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
static void
init_callback_info(png_const_infop info_ptr)
{
   MEMZERO(user_chunk_data);
   user_chunk_data.info_ptr = info_ptr;
}

static int
set_location(png_structp png_ptr, struct user_chunk_data *data, int what)
{
   int location;

   if ((data->location[0] & what) || (data->location[1] & what))
      return 0; /* already have one of these */

   /* Find where we are (the code below zeros info_ptr to indicate that the
    * chunks before the first IDAT have been read.)
    */
   if (data->info_ptr == NULL) /* after IDAT */
      location = what | after_IDAT;

   else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE))
      location = what | before_IDAT;

   else
      location = what | before_PLTE;

   if (data->location[0] == 0)
      data->location[0] = location;

   else
      data->location[1] = location;

   return 1; /* handled */
}
644

645
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
646 647
   png_unknown_chunkp chunk)
{
648 649 650 651 652
   struct user_chunk_data *my_user_chunk_data =
      (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr);

   if (my_user_chunk_data == NULL)
      png_error(png_ptr, "lost user chunk pointer");
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672

   /* Return one of the following:
    *    return (-n);  chunk had an error
    *    return (0);  did not recognize
    *    return (n);  success
    *
    * The unknown chunk structure contains the chunk data:
    * png_byte name[5];
    * png_byte *data;
    * png_size_t size;
    *
    * Note that libpng has already taken care of the CRC handling.
    */

   if (chunk->name[0] == 115 && chunk->name[1] ==  84 &&     /* s  T */
       chunk->name[2] ==  69 && chunk->name[3] ==  82)       /* E  R */
      {
         /* Found sTER chunk */
         if (chunk->size != 1)
            return (-1); /* Error return */
673

674 675
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
676

677 678 679 680 681 682 683 684
         if (set_location(png_ptr, my_user_chunk_data, have_sTER))
         {
            my_user_chunk_data->sTER_mode=chunk->data[0];
            return (1);
         }

         else
            return (0); /* duplicate sTER - give it to libpng */
685 686 687 688 689 690 691 692 693 694 695
      }

   if (chunk->name[0] != 118 || chunk->name[1] != 112 ||    /* v  p */
       chunk->name[2] !=  65 || chunk->name[3] != 103)      /* A  g */
      return (0); /* Did not recognize */

   /* Found ImageMagick vpAg chunk */

   if (chunk->size != 9)
      return (-1); /* Error return */

696 697
   if (!set_location(png_ptr, my_user_chunk_data, have_vpAg))
      return (0);  /* duplicate vpAg */
698

699 700 701
   my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data);
   my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4);
   my_user_chunk_data->vpAg_units = chunk->data[8];
702 703

   return (1);
704 705 706 707 708 709 710 711 712 713
}

#ifdef PNG_WRITE_SUPPORTED
static void
write_sTER_chunk(png_structp write_ptr)
{
   png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};

   if (verbose)
      fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode);
714

715
   png_write_chunk(write_ptr, png_sTER, &user_chunk_data.sTER_mode, 1);
716
}
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759

static void
write_vpAg_chunk(png_structp write_ptr)
{
   png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};

   png_byte vpag_chunk_data[9];

   if (verbose)
      fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
        (unsigned long)user_chunk_data.vpAg_width,
        (unsigned long)user_chunk_data.vpAg_height,
        user_chunk_data.vpAg_units);

   png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width);
   png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height);
   vpag_chunk_data[8] = user_chunk_data.vpAg_units;
   png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
}

static void
write_chunks(png_structp write_ptr, int location)
{
   int i;

   /* Notice that this preserves the original chunk order, however chunks
    * intercepted by the callback will be written *after* chunks passed to
    * libpng.  This will actually reverse a pair of sTER chunks or a pair of
    * vpAg chunks, resulting in an error later.  This is not worth worrying
    * about - the chunks should not be duplicated!
    */
   for (i=0; i<2; ++i)
   {
      if (user_chunk_data.location[i] == (location | have_sTER))
         write_sTER_chunk(write_ptr);

      else if (user_chunk_data.location[i] == (location | have_vpAg))
         write_vpAg_chunk(write_ptr);
   }
}
#endif /* PNG_WRITE_SUPPORTED */
#else /* !PNG_READ_USER_CHUNKS_SUPPORTED */
#  define write_chunks(pp,loc) ((void)0)
760 761 762
#endif
/* END of code to demonstrate user chunk support */

763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
/* START of code to check that libpng has the required text support; this only
 * checks for the write support because if read support is missing the chunk
 * will simply not be reported back to pngtest.
 */
#ifdef PNG_TEXT_SUPPORTED
static void
pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr,
   int num_text)
{
   while (num_text > 0)
   {
      switch (text_ptr[--num_text].compression)
      {
         case PNG_TEXT_COMPRESSION_NONE:
            break;

         case PNG_TEXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_zTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         default:
            /* This is an error */
            png_error(png_ptr, "invalid text chunk compression field");
            break;
      }
   }
}
#endif
/* END of code to check that libpng has the required text support */

802
/* Test one file */
803
static int
804
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
805
{
806 807
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
808
   pngtest_error_parameters error_parameters;
809 810 811 812 813 814 815 816 817 818 819
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
G
Guy Schalnat 已提交
820
   png_bytep row_buf;
G
Guy Schalnat 已提交
821
   png_uint_32 y;
A
Andreas Dilger 已提交
822 823 824
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
825

826
   row_buf = NULL;
827
   error_parameters.file_name = inname;
G
Guy Schalnat 已提交
828

A
Andreas Dilger 已提交
829
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
830 831
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
832
      return (1);
G
Guy Schalnat 已提交
833 834
   }

A
Andreas Dilger 已提交
835
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
836
   {
G
Guy Schalnat 已提交
837
      fprintf(STDERR, "Could not open output file %s\n", outname);
838
      FCLOSE(fpin);
839
      return (1);
G
Guy Schalnat 已提交
840 841
   }

842
   pngtest_debug("Allocating read and write structures");
843
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
844 845
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
846
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
847
#else
848 849
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
850
#endif
851 852
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
853

854
#ifdef PNG_WRITE_SUPPORTED
855
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
856 857 858
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
859
#else
860 861
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
862
#endif
863 864
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
865
#endif
866
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
867
   read_info_ptr = png_create_info_struct(read_ptr);
868
   end_info_ptr = png_create_info_struct(read_ptr);
869 870
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
871
   write_end_info_ptr = png_create_info_struct(write_ptr);
872
#endif
G
Guy Schalnat 已提交
873

874 875 876 877 878 879
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   init_callback_info(read_info_ptr);
   png_set_read_user_chunk_fn(read_ptr, &user_chunk_data,
     read_user_chunk_callback);
#endif

880
#ifdef PNG_SETJMP_SUPPORTED
881
   pngtest_debug("Setting jmpbuf for read struct");
882
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
883
   {
884
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
885 886
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
887
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
888
#ifdef PNG_WRITE_SUPPORTED
889
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
890
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
891
#endif
892 893
      FCLOSE(fpin);
      FCLOSE(fpout);
894
      return (1);
G
Guy Schalnat 已提交
895
   }
A
Andreas Dilger 已提交
896

897
#ifdef PNG_WRITE_SUPPORTED
898
   pngtest_debug("Setting jmpbuf for write struct");
899

900
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
901
   {
902
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
903
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
904
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
905
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
906
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
907
#endif
908 909
      FCLOSE(fpin);
      FCLOSE(fpout);
910
      return (1);
G
Guy Schalnat 已提交
911
   }
912
#endif
A
Andreas Dilger 已提交
913
#endif
914

915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
   if (strict)
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);

#ifdef PNG_WRITE_SUPPORTED
      /* Treat them as errors on write */
      png_set_benign_errors(write_ptr, 0);
#endif

      /* if strict is not set, then app warnings and errors are treated as
       * warnings in release builds, but not in unstable builds; this can be
       * changed with '--relaxed'.
       */
   }

   else if (relaxed)
   {
      /* Allow application (pngtest) errors and warnings to pass */
      png_set_benign_errors(read_ptr, 1);

#ifdef PNG_WRITE_SUPPORTED
      png_set_benign_errors(write_ptr, 1);
#endif
   }

941
   pngtest_debug("Initializing input and output streams");
942
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
943
   png_init_io(read_ptr, fpin);
944
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
945
   png_init_io(write_ptr, fpout);
946
#  endif
947
#else
948
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
949
#  ifdef PNG_WRITE_SUPPORTED
950
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
951
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
952
      pngtest_flush);
953
#    else
954
      NULL);
955 956
#    endif
#  endif
957
#endif
958

959
   if (status_dots_requested == 1)
960
   {
961
#ifdef PNG_WRITE_SUPPORTED
962
      png_set_write_status_fn(write_ptr, write_row_callback);
963
#endif
964 965
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
966

967 968
   else
   {
969
#ifdef PNG_WRITE_SUPPORTED
970
      png_set_write_status_fn(write_ptr, NULL);
971
#endif
972
      png_set_read_status_fn(read_ptr, NULL);
973 974
   }

975
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
976
   {
977
      int i;
978

979 980
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
981

982
      png_set_read_user_transform_fn(read_ptr, count_filters);
983 984
   }
#endif
985
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
986
   zero_samples = 0;
987 988
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
989

990 991 992 993 994 995 996 997 998 999
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
   /* Preserve all the unknown chunks, if possible.  If this is disabled then,
    * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use
    * libpng to *save* the unknown chunks on read (because we can't switch the
    * save option on!)
    *
    * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all
    * unknown chunks and write will write them all.
    */
#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
1000 1001
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
1002
#endif
1003
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1004
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1005
      NULL, 0);
1006
#endif
1007 1008
#endif

1009
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
1010
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
1011

1012 1013 1014 1015 1016 1017 1018 1019 1020
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   /* This is a bit of a hack; there is no obvious way in the callback function
    * to determine that the chunks before the first IDAT have been read, so
    * remove the info_ptr (which is only used to determine position relative to
    * PLTE) here to indicate that we are after the IDAT.
    */
   user_chunk_data.info_ptr = NULL;
#endif

1021
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
1022 1023
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
1024

A
Andreas Dilger 已提交
1025 1026 1027 1028
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
1029
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
1030
            color_type, interlace_type, compression_type, filter_type);
1031 1032 1033
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
1034 1035
      }
   }
1036 1037
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1038
   {
1039
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1040
         blue_y;
1041

1042 1043
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y))
A
Andreas Dilger 已提交
1044
      {
1045 1046
         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
A
Andreas Dilger 已提交
1047
      }
G
Guy Schalnat 已提交
1048
   }
A
Andreas Dilger 已提交
1049
#endif
1050
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1051
   {
1052
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1053

1054 1055
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1056 1057
   }
#endif
1058
#else /* Use floating point versions */
1059 1060
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1061 1062 1063
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1064

1065 1066 1067 1068 1069 1070 1071 1072
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
1073
#ifdef PNG_gAMA_SUPPORTED
1074 1075 1076 1077 1078 1079 1080
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1081 1082
#endif /* Floating point */
#endif /* Fixed point */
1083
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1084
   {
1085
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1086
      png_bytep profile;
1087
      png_uint_32 proflen;
1088
      int compression_type;
A
Andreas Dilger 已提交
1089

1090 1091
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1092
      {
1093 1094
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1095
      }
G
Guy Schalnat 已提交
1096
   }
1097
#endif
1098
#ifdef PNG_sRGB_SUPPORTED
1099
   {
1100
      int intent;
1101 1102 1103 1104

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1105
#endif
1106 1107 1108 1109 1110 1111 1112
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1113
#ifdef PNG_bKGD_SUPPORTED
1114 1115 1116 1117 1118 1119 1120 1121 1122
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1123
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1124
   {
A
Andreas Dilger 已提交
1125 1126 1127 1128
      png_uint_16p hist;

      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1129
   }
A
Andreas Dilger 已提交
1130
#endif
1131
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1132
   {
1133
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1134
      int unit_type;
G
Guy Schalnat 已提交
1135

1136
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1137
          &unit_type))
A
Andreas Dilger 已提交
1138 1139 1140 1141 1142
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1143
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
   {
      png_charp purpose, units;
      png_charpp params;
      png_int_32 X0, X1;
      int type, nparams;

      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
         &nparams, &units, &params))
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1158
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1159 1160 1161 1162 1163 1164 1165 1166
   {
      png_uint_32 res_x, res_y;
      int unit_type;

      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1167
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1168
   {
1169
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1170

1171 1172
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1173
   }
1174
#endif
1175
#ifdef PNG_sCAL_SUPPORTED
1176
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
1177
   {
1178
      int unit;
1179
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1180

1181 1182
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1183
      {
1184
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1185 1186 1187
      }
   }
#else
1188
#ifdef PNG_FIXED_POINT_SUPPORTED
1189
   {
1190
      int unit;
1191
      png_charp scal_width, scal_height;
1192

1193 1194
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1195
      {
1196 1197
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1198 1199
      }
   }
G
Guy Schalnat 已提交
1200
#endif
1201 1202
#endif
#endif
1203
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1204 1205 1206 1207 1208 1209
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1210
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1211

1212 1213
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1214
         if (verbose)
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
         {
            int i;

            printf("\n");
            for (i=0; i<num_text; i++)
            {
               printf("   Text compression[%d]=%d\n",
                     i, text_ptr[i].compression);
            }
         }
1225

A
Andreas Dilger 已提交
1226 1227 1228 1229
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1230
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1231 1232 1233 1234 1235 1236
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1237
#ifdef PNG_TIME_RFC1123_SUPPORTED
1238
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1239
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1240 1241

         else
1242 1243 1244 1245
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1246

1247 1248
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1249
      }
A
Andreas Dilger 已提交
1250 1251
   }
#endif
1252
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1253
   {
1254
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1255
      int num_trans;
1256
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1257

1258
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1259
         &trans_color))
A
Andreas Dilger 已提交
1260
      {
1261
         int sample_max = (1 << bit_depth);
1262
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1263
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1264
             (int)trans_color->gray > sample_max) ||
1265
             (color_type == PNG_COLOR_TYPE_RGB &&
1266 1267 1268
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1269
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1270
               trans_color);
A
Andreas Dilger 已提交
1271 1272 1273
      }
   }
#endif
1274
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1275 1276
   {
      png_unknown_chunkp unknowns;
1277
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1278
         &unknowns);
1279

1280 1281 1282 1283
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1284
#if PNG_LIBPNG_VER < 10600
1285
         /* Copy the locations from the read_info_ptr.  The automatically
1286 1287
          * generated locations in write_end_info_ptr are wrong prior to 1.6.0
          * because they are reset from the write pointer (removed in 1.6.0).
1288
          */
1289 1290 1291 1292 1293 1294 1295
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
1296 1297 1298
      }
   }
#endif
A
Andreas Dilger 已提交
1299

1300
#ifdef PNG_WRITE_SUPPORTED
1301
   pngtest_debug("Writing info struct");
1302

1303 1304 1305 1306
   /* Write the info in two steps so that if we write the 'unknown' chunks here
    * they go to the correct place.
    */
   png_write_info_before_PLTE(write_ptr, write_info_ptr);
1307

1308
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1309

1310
   png_write_info(write_ptr, write_info_ptr);
1311

1312
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1313
#endif
A
Andreas Dilger 已提交
1314

1315
#ifdef SINGLE_ROWBUF_ALLOC
1316
   pngtest_debug("Allocating row buffer...");
1317
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1318
      png_get_rowbytes(read_ptr, read_info_ptr));
1319

1320
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1321
#endif /* SINGLE_ROWBUF_ALLOC */
1322
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1323

1324 1325
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1326
   num_pass = png_set_interlace_handling(read_ptr);
1327
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1328
   png_set_interlace_handling(write_ptr);
1329
#  endif
1330
#else
1331
   num_pass = 1;
1332
#endif
A
Andreas Dilger 已提交
1333

1334 1335 1336 1337 1338
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1339 1340
   for (pass = 0; pass < num_pass; pass++)
   {
1341
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1342 1343
      for (y = 0; y < height; y++)
      {
1344
#ifndef SINGLE_ROWBUF_ALLOC
1345
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1346 1347
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1348

1349
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1350
            png_get_rowbytes(read_ptr, read_info_ptr));
1351

1352
#endif /* !SINGLE_ROWBUF_ALLOC */
1353
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1354 1355

#ifdef PNG_WRITE_SUPPORTED
1356 1357 1358 1359 1360
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1361
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1362 1363 1364 1365 1366
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1367 1368 1369
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1370
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1371
         png_free(read_ptr, row_buf);
1372
         row_buf = NULL;
1373
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1374 1375 1376
      }
   }

1377
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1378
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1379
#endif
1380
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1381
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1382 1383
#endif

1384
   pngtest_debug("Reading and writing end_info data");
1385

A
Andreas Dilger 已提交
1386
   png_read_end(read_ptr, end_info_ptr);
1387
#ifdef PNG_TEXT_SUPPORTED
1388 1389 1390 1391 1392 1393
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1394
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

         if (verbose)
         {
            int i;

            printf("\n");
            for (i=0; i<num_text; i++)
            {
               printf("   Text compression[%d]=%d\n",
                     i, text_ptr[i].compression);
            }
         }

1410 1411 1412 1413
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1414
#ifdef PNG_tIME_SUPPORTED
1415 1416 1417 1418 1419 1420
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1421
#ifdef PNG_TIME_RFC1123_SUPPORTED
1422
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1423
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1424 1425

         else
1426 1427 1428 1429
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1430

1431 1432 1433 1434
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1435
#endif
1436
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1437 1438
   {
      png_unknown_chunkp unknowns;
1439
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1440
         &unknowns);
1441

1442 1443 1444 1445
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1446
#if PNG_LIBPNG_VER < 10600
1447
         /* Copy the locations from the read_info_ptr.  The automatically
1448 1449
          * generated locations in write_end_info_ptr are wrong prior to 1.6.0
          * because they are reset from the write pointer (removed in 1.6.0).
1450
          */
1451 1452 1453 1454 1455 1456 1457
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
                unknowns[i].location);
         }
#endif
1458 1459
      }
   }
1460
#endif
1461

1462
#ifdef PNG_WRITE_SUPPORTED
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
    * This is here just to make pngtest replicate the results from libpng
    * versions prior to 1.5.4, and to test this new API.
    */
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

   /* When the unknown vpAg/sTER chunks are written by pngtest the only way to
    * do it is to write them *before* calling png_write_end.  When unknown
    * chunks are written by libpng, however, they are written just before IEND.
    * There seems to be no way round this, however vpAg/sTER are not expected
    * after IDAT.
    */
   write_chunks(write_ptr, after_IDAT);

1479
   png_write_end(write_ptr, write_end_info_ptr);
1480
#endif
1481

1482
#ifdef PNG_EASY_ACCESS_SUPPORTED
1483
   if (verbose)
1484 1485 1486 1487
   {
      png_uint_32 iwidth, iheight;
      iwidth = png_get_image_width(write_ptr, write_info_ptr);
      iheight = png_get_image_height(write_ptr, write_info_ptr);
1488
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1489
         (unsigned long)iwidth, (unsigned long)iheight);
1490 1491
   }
#endif
G
Guy Schalnat 已提交
1492

1493
   pngtest_debug("Destroying data structs");
1494
#ifdef SINGLE_ROWBUF_ALLOC
1495
   pngtest_debug("destroying row_buf for read_ptr");
1496
   png_free(read_ptr, row_buf);
1497
   row_buf = NULL;
1498
#endif /* SINGLE_ROWBUF_ALLOC */
1499
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1500
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1501
#ifdef PNG_WRITE_SUPPORTED
1502
   pngtest_debug("destroying write_end_info_ptr");
1503
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1504
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1505
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1506
#endif
1507
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1508

1509 1510
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1511

1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
   /* Summarize any warnings or errors and in 'strict' mode fail the test.
    * Unsupported chunks can result in warnings, in that case ignore the strict
    * setting, otherwise fail the test on warnings as well as errors.
    */
   if (error_count > 0)
   {
      /* We don't really expect to get here because of the setjmp handling
       * above, but this is safe.
       */
      fprintf(STDERR, "\n  %s: %d libpng errors found (%d warnings)",
         inname, error_count, warning_count);

      if (strict != 0)
         return (1);
   }

#  ifdef PNG_WRITE_SUPPORTED
      /* If there we no write support nothing was written! */
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
            inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
         inname, warning_count);

      if (strict != 0)
         return (1);
   }

1546
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1547
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1548
   {
G
Guy Schalnat 已提交
1549
      fprintf(STDERR, "Could not find file %s\n", inname);
1550
      return (1);
G
Guy Schalnat 已提交
1551 1552
   }

A
Andreas Dilger 已提交
1553
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1554
   {
G
Guy Schalnat 已提交
1555
      fprintf(STDERR, "Could not find file %s\n", outname);
1556
      FCLOSE(fpin);
1557
      return (1);
G
Guy Schalnat 已提交
1558
   }
A
Andreas Dilger 已提交
1559

1560
#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
G
Guy Schalnat 已提交
1561
   {
1562
      int wrote_question = 0;
1563

1564
      for (;;)
1565
      {
1566 1567 1568 1569 1570 1571
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];


         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1572

1573
         if (num_in != num_out)
1574
         {
1575 1576
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);
1577

1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589
            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
                 inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
                 "\n   filtering heuristic (libpng default), compression");
               fprintf(STDERR,
                 " level (zlib default),\n   and zlib version (%s)?\n\n",
                 ZLIB_VERSION);
               wrote_question = 1;
            }
1590

1591 1592
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1593

1594 1595
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1596

1597 1598 1599
            else
              return (0);
         }
1600

1601 1602
         if (!num_in)
            break;
1603

1604
         if (memcmp(inbuf, outbuf, num_in))
1605
         {
1606 1607 1608 1609 1610 1611
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1612
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1613 1614 1615 1616 1617 1618 1619 1620
                    inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
                 "\n   filtering heuristic (libpng default), compression");
               fprintf(STDERR,
                 " level (zlib default),\n   and zlib version (%s)?\n\n",
                 ZLIB_VERSION);
               wrote_question = 1;
            }
1621

1622 1623
            FCLOSE(fpin);
            FCLOSE(fpout);
1624

1625 1626 1627 1628 1629 1630 1631
            /* NOTE: the unsupported_chunks escape is permitted here because
             * unsupported text chunk compression will result in the compression
             * mode being changed (to NONE) yet, in the test case, the result
             * can be exactly the same size!
             */
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
1632

1633 1634 1635
            else
              return (0);
         }
G
Guy Schalnat 已提交
1636 1637
      }
   }
1638
#endif /* PNG_WRITE_SUPPORTED */
G
Guy Schalnat 已提交
1639

1640 1641
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1642

1643
   return (0);
G
Guy Schalnat 已提交
1644
}
G
Guy Schalnat 已提交
1645

1646
/* Input and output filenames */
1647
#ifdef RISCOS
1648 1649
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1650
#else
1651 1652
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1653 1654 1655 1656 1657 1658 1659 1660
#endif

int
main(int argc, char *argv[])
{
   int multiple = 0;
   int ierror = 0;

1661
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1662
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1663
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1664
   /* Show the version of libpng used in building the library */
1665 1666
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1667
      png_get_header_version(NULL));
1668

1669
   /* Show the version of libpng used in building the application */
1670
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1671
      PNG_HEADER_VERSION_STRING);
1672 1673

   /* Do some consistency checking on the memory allocation settings, I'm
1674 1675 1676 1677
    * not sure this matters, but it is nice to know, the first of these
    * tests should be impossible because of the way the macros are set
    * in pngconf.h
    */
1678
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1679
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1680
#endif
1681
   /* I think the following can happen. */
1682
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1683
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1684
#endif
1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
         "Warning: versions are different between png.h and png.c\n");
      fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
      fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
      ++ierror;
   }

   if (argc > 1)
   {
1697
      if (strcmp(argv[1], "-m") == 0)
1698
      {
1699
         multiple = 1;
1700 1701
         status_dots_requested = 0;
      }
1702

1703 1704 1705 1706 1707
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1708
         status_dots_requested = 1;
1709
      }
1710

1711 1712 1713
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1714
         status_dots_requested = 1;
1715 1716
         inname = argv[2];
      }
1717

1718 1719 1720 1721 1722 1723
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1724 1725 1726 1727 1728 1729 1730 1731 1732 1733
         relaxed = 0;
      }

      else if (strcmp(argv[1], "--relaxed") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict = 0;
         relaxed++;
1734 1735
      }

1736
      else
1737
      {
1738
         inname = argv[1];
1739 1740
         status_dots_requested = 0;
      }
1741 1742
   }

1743 1744
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1745

1746
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1747
   {
1748 1749
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1750
        argv[0], argv[0]);
1751 1752 1753 1754
     fprintf(STDERR,
       "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
     fprintf(STDERR,
       "  with -m %s is used as a temporary file\n", outname);
1755 1756 1757 1758 1759 1760
     exit(1);
   }

   if (multiple)
   {
      int i;
1761
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1762 1763
      int allocation_now = current_allocation;
#endif
1764
      for (i=2; i<argc; ++i)
1765
      {
1766
         int kerror;
1767
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1768
         kerror = test_one_file(argv[i], outname);
1769
         if (kerror == 0)
1770
         {
1771 1772 1773
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1774
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1775
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1776
               (unsigned long)zero_samples);
1777
#else
1778
            fprintf(STDERR, " PASS\n");
1779
#endif
1780
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1781 1782
            for (k = 0; k<256; k++)
               if (filters_used[k])
1783
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1784
                     k, (unsigned long)filters_used[k]);
1785
#endif
1786
#ifdef PNG_TIME_RFC1123_SUPPORTED
1787 1788
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1789

1790 1791 1792
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1793

1794 1795
         else
         {
1796 1797
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1798
         }
1799
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1800 1801
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1802
               current_allocation - allocation_now);
1803

1804 1805
         if (current_allocation != 0)
         {
1806 1807 1808 1809
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
1810

1811 1812
            while (pinfo != NULL)
            {
1813
               fprintf(STDERR, " %lu bytes at %x\n",
1814
                 (unsigned long)pinfo->size,
1815
                 (unsigned int)pinfo->pointer);
1816
               pinfo = pinfo->next;
1817
            }
1818
         }
1819 1820
#endif
      }
1821
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1822
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1823
            current_allocation);
1824
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1825
            maximum_allocation);
1826 1827 1828 1829
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1830
#endif
1831
   }
1832

1833 1834
   else
   {
1835
      int i;
1836
      for (i = 0; i<3; ++i)
1837
      {
1838
         int kerror;
1839
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1840 1841
         int allocation_now = current_allocation;
#endif
1842 1843 1844 1845 1846 1847
         if (i == 1)
            status_dots_requested = 1;

         else if (verbose == 0)
            status_dots_requested = 0;

1848
         if (i == 0 || verbose == 1 || ierror != 0)
1849
            fprintf(STDERR, "\n Testing %s:", inname);
1850

1851
         kerror = test_one_file(inname, outname);
1852

1853
         if (kerror == 0)
1854
         {
1855
            if (verbose == 1 || i == 2)
1856
            {
1857
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1858
                int k;
1859
#endif
1860
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1861
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1862
                   (unsigned long)zero_samples);
1863 1864 1865
#else
                fprintf(STDERR, " PASS\n");
#endif
1866
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1867 1868
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1869
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1870
                         k, (unsigned long)filters_used[k]);
1871
#endif
1872
#ifdef PNG_TIME_RFC1123_SUPPORTED
1873 1874
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1875 1876
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1877
         }
1878

1879 1880
         else
         {
1881
            if (verbose == 0 && i != 2)
1882
               fprintf(STDERR, "\n Testing %s:", inname);
1883

1884 1885
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1886
         }
1887
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1888 1889
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1890
               current_allocation - allocation_now);
1891

1892 1893
         if (current_allocation != 0)
         {
1894
             memory_infop pinfo = pinformation;
1895

1896 1897
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
1898

1899 1900
             while (pinfo != NULL)
             {
1901 1902
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1903 1904 1905 1906
                pinfo = pinfo->next;
             }
          }
#endif
1907
       }
1908
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1909
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1910
          current_allocation);
1911
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1912
          maximum_allocation);
1913 1914 1915 1916
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1917
#endif
1918 1919
   }

1920 1921 1922 1923
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1924
   fprintf(STDERR, " CPU time used = %.3f seconds",
1925
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1926
   fprintf(STDERR, " (decoding %.3f,\n",
1927
      t_decode/(float)CLOCKS_PER_SEC);
1928
   fprintf(STDERR, "        encoding %.3f ,",
1929
      t_encode/(float)CLOCKS_PER_SEC);
1930
   fprintf(STDERR, " other %.3f seconds)\n\n",
1931 1932 1933
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1934
   if (ierror == 0)
1935
      fprintf(STDERR, " libpng passes test\n");
1936

1937
   else
1938
      fprintf(STDERR, " libpng FAILS test\n");
1939

1940
   return (int)(ierror != 0);
1941
}
1942 1943 1944 1945 1946 1947 1948 1949 1950
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
   return 0;
}
#endif
1951

1952
/* Generate a compiler error if there is an old png.h in the search path. */
1953
typedef png_libpng_version_1_6_2beta02 Your_png_h_is_not_version_1_6_2beta02;