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.0 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2012 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
static int relaxed = 0;
99 100 101
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
#ifdef PNG_WRITE_SUPPORTED
153
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 419
   ++warning_count;

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

423
   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
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;
601

602 603 604 605 606 607 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
/* 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

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 714 715 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
}

#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);

   png_write_chunk(write_ptr, png_sTER, &user_chunk_data.sTER_mode, 1);
}

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);
752

753 754 755
      else if (user_chunk_data.location[i] == (location | have_vpAg))
         write_vpAg_chunk(write_ptr);
   }
756
}
757 758 759
#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
   if (strict)
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);
919 920

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

925 926 927 928 929
      /* 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'.
       */
   }
930

931 932 933 934 935 936 937 938
   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
939 940
   }

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
#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
991 992 993 994 995 996 997 998 999
   /* 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
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1245
         }
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
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409
         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
#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

1471 1472 1473 1474 1475 1476 1477
   /* 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);

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

1481
#ifdef PNG_EASY_ACCESS_SUPPORTED
1482
   if (verbose)
1483 1484 1485 1486
   {
      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);
1487
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1488
         (unsigned long)iwidth, (unsigned long)iheight);
1489 1490
   }
#endif
G
Guy Schalnat 已提交
1491

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

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

1511 1512 1513 1514 1515 1516 1517 1518 1519
   /* 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.
       */
1520
      fprintf(STDERR, "\n  %s: %d libpng errors found (%d warnings)",
1521 1522 1523 1524 1525 1526
         inname, error_count, warning_count);

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

1527 1528 1529 1530 1531 1532 1533 1534
#  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
1535 1536 1537

   else if (warning_count > 0)
   {
1538
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
1539 1540 1541 1542 1543 1544
         inname, warning_count);

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

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

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

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

1563
      for (;;)
G
Guy Schalnat 已提交
1564
      {
1565 1566
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];
1567

1568 1569 1570 1571 1572

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

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

1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
            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;
            }
1589

1590 1591
            FCLOSE(fpin);
            FCLOSE(fpout);
1592

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

1596 1597 1598
            else
              return (0);
         }
G
Guy Schalnat 已提交
1599

1600 1601
         if (!num_in)
            break;
1602

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

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1611
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1612 1613 1614 1615 1616 1617 1618 1619
                    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;
            }
1620

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

1624 1625 1626 1627 1628 1629 1630
            /* 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);
1631

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

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

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

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

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

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

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

   /* Do some consistency checking on the memory allocation settings, I'm
1673 1674 1675 1676
    * 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
    */
1677
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1678
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1679
#endif
1680
   /* I think the following can happen. */
1681
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1682
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1683
#endif
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695

   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)
   {
1696
      if (strcmp(argv[1], "-m") == 0)
1697
      {
1698
         multiple = 1;
1699 1700
         status_dots_requested = 0;
      }
1701

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

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

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

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

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

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

1745
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1746
   {
1747 1748
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1749
        argv[0], argv[0]);
1750 1751 1752 1753
     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);
1754 1755 1756 1757 1758 1759
     exit(1);
   }

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

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

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

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

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

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

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

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

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

1850
         kerror = test_one_file(inname, outname);
1851

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

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

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

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

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

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

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

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

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

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

1951
/* Generate a compiler error if there is an old png.h in the search path. */
1952
typedef png_libpng_version_1_6_0beta31 Your_png_h_is_not_version_1_6_0beta31;