pngtest.c 56.8 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.9 [February 6, 2014]
5
 * Copyright (c) 1998-2014 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
/* Known chunks that exist in pngtest.png must be supported or pngtest will fail
 * simply as a result of re-ordering them.  This may be fixed in 1.7
48 49 50 51 52
 *
 * pngtest allocates a single row buffer for each row and overwrites it,
 * therefore if the write side doesn't support the writing of interlaced images
 * nothing can be done for an interlaced image (and the code below will fail
 * horribly trying to write extra data after writing garbage).
53 54 55 56 57 58 59 60 61 62 63 64 65
 */
#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\
   defined PNG_READ_bKGD_SUPPORTED &&\
   defined PNG_READ_cHRM_SUPPORTED &&\
   defined PNG_READ_gAMA_SUPPORTED &&\
   defined PNG_READ_oFFs_SUPPORTED &&\
   defined PNG_READ_pCAL_SUPPORTED &&\
   defined PNG_READ_pHYs_SUPPORTED &&\
   defined PNG_READ_sBIT_SUPPORTED &&\
   defined PNG_READ_sCAL_SUPPORTED &&\
   defined PNG_READ_sRGB_SUPPORTED &&\
   defined PNG_READ_tEXt_SUPPORTED &&\
   defined PNG_READ_tIME_SUPPORTED &&\
66 67 68 69 70 71 72 73
   defined PNG_READ_zTXt_SUPPORTED &&\
   defined PNG_WRITE_INTERLACING_SUPPORTED

#ifdef PNG_ZLIB_HEADER
#  include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */
#else
#  include "zlib.h"
#endif
74

75 76 77 78
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
79
#define FCLOSE(file) fclose(file)
80

81
#ifndef PNG_STDIO_SUPPORTED
82
typedef FILE                * png_FILE_p;
83 84
#endif

85
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
86
#ifndef PNG_DEBUG
87 88 89
#  define PNG_DEBUG 0
#endif

90 91 92 93 94 95 96 97 98
#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
99

100
#if !PNG_DEBUG
101
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
102
#endif
A
Andreas Dilger 已提交
103

104 105 106 107
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

108
#ifndef PNG_FLOATING_POINT_SUPPORTED
109 110 111
#undef PNGTEST_TIMING
#endif

112 113 114 115 116
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

117
#ifdef PNG_TIME_RFC1123_SUPPORTED
118
#define PNG_tIME_STRING_LENGTH 29
119
static int tIME_chunk_present = 0;
120
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
121 122
#endif

123
static int verbose = 0;
124
static int strict = 0;
125 126 127 128
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 */
129

130 131 132 133 134
/* 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

135 136 137 138 139 140 141 142 143 144 145
/* 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))

146
/* Example of using row callbacks to make a simple progress meter */
147 148 149
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
150

151
static void PNGCBAPI
152
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
153
{
154 155
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
156

157 158 159 160 161 162
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
163

164
   status_dots--;
165

166 167 168 169 170
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
171

172
   fprintf(stdout, "r");
173
}
174

175 176
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
177
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
178
{
179 180
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
181

182
   fprintf(stdout, "w");
183
}
184
#endif
185 186


187
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
188
/* Example of using user transform callback (we don't transform anything,
189 190 191
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
192
static png_uint_32 filters_used[256];
193
static void PNGCBAPI
194 195
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
196
   if (png_ptr != NULL && row_info != NULL)
197
      ++filters_used[*(data - 1)];
198 199 200
}
#endif

201
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
202
/* Example of using user transform callback (we don't transform anything,
203 204
 * but merely count the zero samples)
 */
205

206
static png_uint_32 zero_samples;
207

208
static void PNGCBAPI
209
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
210 211
{
   png_bytep dp = data;
212 213
   if (png_ptr == NULL)
      return;
214

215
   /* Contents of row_info:
216 217 218 219 220 221 222 223
    *  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)
    */

224
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
225

226
    if (row_info->color_type == 0 || row_info->color_type == 3)
227
    {
228
       int pos = 0;
229
       png_uint_32 n, nstop;
230

231
       for (n = 0, nstop=row_info->width; n<nstop; n++)
232
       {
233
          if (row_info->bit_depth == 1)
234
          {
235 236
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
237

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

245
          if (row_info->bit_depth == 2)
246
          {
247 248
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
249

250
             if (pos == 8)
251
             {
252
                pos = 0;
253 254
                dp++;
             }
255
          }
256

257
          if (row_info->bit_depth == 4)
258
          {
259 260
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
261

262
             if (pos == 8)
263
             {
264
                pos = 0;
265 266
                dp++;
             }
267
          }
268

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
    else /* Other color types */
282
    {
283
       png_uint_32 n, nstop;
284 285
       int channel;
       int color_channels = row_info->channels;
286
       if (row_info->color_type > 3)color_channels--;
287

288
       for (n = 0, nstop=row_info->width; n<nstop; n++)
289 290 291
       {
          for (channel = 0; channel < color_channels; channel++)
          {
292
             if (row_info->bit_depth == 8)
293 294
                if (*dp++ == 0)
                   zero_samples++;
295

296
             if (row_info->bit_depth == 16)
297
             {
298 299
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
300

301 302 303
                dp+=2;
             }
          }
304
          if (row_info->color_type > 3)
305 306
          {
             dp++;
307 308
             if (row_info->bit_depth == 16)
                dp++;
309 310 311 312
          }
       }
    }
}
313
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
314

315
#ifndef PNG_STDIO_SUPPORTED
316
/* START of code to validate stdio-free compilation */
317 318 319 320 321 322 323
/* 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.
 */
324

325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
#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

367
static void PNGCBAPI
368
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
369
{
370 371
   png_size_t check = 0;
   png_voidp io_ptr;
372 373 374 375

   /* 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.
    */
376 377 378 379 380
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
381

382 383
   if (check != length)
   {
384
      png_error(png_ptr, "Read Error");
385
   }
386 387 388 389

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

392
#ifdef PNG_WRITE_FLUSH_SUPPORTED
393
static void PNGCBAPI
394
pngtest_flush(png_structp png_ptr)
395
{
396
   /* Do nothing; fflush() is said to be just a waste of energy. */
397
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
398 399
}
#endif
G
Guy Schalnat 已提交
400

401
/* This is the function that does the actual writing of data.  If you are
402 403 404 405
 * 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.
 */
406
static void PNGCBAPI
407
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
408
{
409
   png_size_t check;
410

411
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
412

413 414 415 416
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
417 418 419 420

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
421
}
422
#endif /* !PNG_STDIO_SUPPORTED */
423 424 425 426 427 428

/* 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.
 */
429 430 431 432 433
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

434
static void PNGCBAPI
435
pngtest_warning(png_structp png_ptr, png_const_charp message)
436 437
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
438 439
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
440

441
   ++warning_count;
442

443 444 445 446
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
447 448 449 450 451 452 453
}

/* 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().
 */
454
static void PNGCBAPI
455
pngtest_error(png_structp png_ptr, png_const_charp message)
456
{
457 458
   ++error_count;

459
   pngtest_warning(png_ptr, message);
460
   /* We can return because png_error calls the default handler, which is
461 462
    * actually OK in this case.
    */
463
}
464

465 466
/* END of code to validate stdio-free compilation */

467
/* START of code to validate memory allocation and deallocation */
468
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
469 470

/* Allocate memory.  For reasonable files, size should never exceed
471 472 473 474 475 476 477 478
 * 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.
 */
479 480
typedef struct memory_information
{
481
   png_alloc_size_t          size;
482
   png_voidp                 pointer;
483
   struct memory_information *next;
484
} memory_information;
485
typedef memory_information *memory_infop;
486 487 488 489

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
490 491
static int total_allocation = 0;
static int num_allocations = 0;
492

493 494 495
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));
496 497

png_voidp
498
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
499
{
500

501
   /* png_malloc has already tested for NULL; png_create_struct calls
502 503
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
504

505
   if (size == 0)
506
      return (NULL);
507 508 509 510

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
511
      /* Disable malloc_fn and free_fn */
512
      memory_infop pinfo;
513
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
514
      pinfo = (memory_infop)png_malloc(png_ptr,
515
         (sizeof *pinfo));
516 517
      pinfo->size = size;
      current_allocation += size;
518 519
      total_allocation += size;
      num_allocations ++;
520

521 522
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
523

524
      pinfo->pointer = png_malloc(png_ptr, size);
525
      /* Restore malloc_fn and free_fn */
526

527 528
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
529

530 531 532 533
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
534
         png_error(png_ptr,
535
           "out of memory in pngtest->png_debug_malloc");
536
      }
537

538 539 540
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
541
      memset(pinfo->pointer, 0xdd, pinfo->size);
542

543
      if (verbose)
544
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
545
            pinfo->pointer);
546

547
      return (png_voidp)(pinfo->pointer);
548 549 550 551
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
552
void PNGCBAPI
553
png_debug_free(png_structp png_ptr, png_voidp ptr)
554 555
{
   if (png_ptr == NULL)
556
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
557

558 559
   if (ptr == 0)
   {
560 561 562 563 564 565 566 567
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
568
      memory_infop *ppinfo = &pinformation;
569

570 571
      for (;;)
      {
572
         memory_infop pinfo = *ppinfo;
573

574 575
         if (pinfo->pointer == ptr)
         {
576 577 578 579 580
            *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
581
               the memory that is to be freed. */
582
            memset(ptr, 0x55, pinfo->size);
583 584
            if (pinfo)
               free(pinfo);
585
            pinfo = NULL;
586 587
            break;
         }
588

589 590
         if (pinfo->next == NULL)
         {
591
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
592 593
            break;
         }
594

595 596 597 598 599
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
600
   if (verbose)
601
      printf("Freeing %p\n", ptr);
602

603 604
   if (ptr)
      free(ptr);
605
   ptr = NULL;
606
}
607
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
608 609
/* END of code to test memory allocation/deallocation */

610

611
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
612 613
/* Demonstration of user chunk support of the sTER and vpAg chunks */

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

617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
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
633

634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
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 */
}
669

670
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
671 672
   png_unknown_chunkp chunk)
{
673 674 675 676 677
   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");
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697

   /* 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 */
698

699 700
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
701

702 703 704 705 706 707 708 709
         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 */
710 711 712 713 714 715 716 717 718 719 720
      }

   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 */

721 722
   if (!set_location(png_ptr, my_user_chunk_data, have_vpAg))
      return (0);  /* duplicate vpAg */
723

724 725 726
   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];
727 728

   return (1);
729 730 731 732 733 734
}

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

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

740
   png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1);
741
}
742 743 744 745

static void
write_vpAg_chunk(png_structp write_ptr)
{
746
   png_byte vpAg[5] = {118, 112,  65, 103, '\0'};
747 748 749 750 751 752 753 754 755 756 757 758

   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;
759
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784
}

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)
785 786 787
#endif
/* END of code to demonstrate user chunk support */

788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
/* 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 */

827
/* Test one file */
828
static int
829
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
830
{
831 832
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
833
   pngtest_error_parameters error_parameters;
834 835 836 837 838 839
   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;
840
   int interlace_preserved = 1;
841 842 843 844 845
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
G
Guy Schalnat 已提交
846
   png_bytep row_buf;
G
Guy Schalnat 已提交
847
   png_uint_32 y;
A
Andreas Dilger 已提交
848
   png_uint_32 width, height;
849
   int num_pass = 1, pass;
A
Andreas Dilger 已提交
850
   int bit_depth, color_type;
851

852
   row_buf = NULL;
853
   error_parameters.file_name = inname;
G
Guy Schalnat 已提交
854

A
Andreas Dilger 已提交
855
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
856 857
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
858
      return (1);
G
Guy Schalnat 已提交
859 860
   }

A
Andreas Dilger 已提交
861
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
862
   {
G
Guy Schalnat 已提交
863
      fprintf(STDERR, "Could not open output file %s\n", outname);
864
      FCLOSE(fpin);
865
      return (1);
G
Guy Schalnat 已提交
866 867
   }

868
   pngtest_debug("Allocating read and write structures");
869
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
870 871
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
872
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
873
#else
874 875
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
876
#endif
877 878
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
879

880
#ifdef PNG_WRITE_SUPPORTED
881
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
882 883 884
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
885
#else
886 887
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
888
#endif
889 890
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
891
#endif
892
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
893
   read_info_ptr = png_create_info_struct(read_ptr);
894
   end_info_ptr = png_create_info_struct(read_ptr);
895 896
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
897
   write_end_info_ptr = png_create_info_struct(write_ptr);
898
#endif
G
Guy Schalnat 已提交
899

900 901 902 903 904 905
#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

906
#ifdef PNG_SETJMP_SUPPORTED
907
   pngtest_debug("Setting jmpbuf for read struct");
908
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
909
   {
910
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
911 912
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
913
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
914
#ifdef PNG_WRITE_SUPPORTED
915
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
916
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
917
#endif
918 919
      FCLOSE(fpin);
      FCLOSE(fpout);
920
      return (1);
G
Guy Schalnat 已提交
921
   }
A
Andreas Dilger 已提交
922

923
#ifdef PNG_WRITE_SUPPORTED
924
   pngtest_debug("Setting jmpbuf for write struct");
925

926
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
927
   {
928
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
929
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
930
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
931
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
932
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
933
#endif
934 935
      FCLOSE(fpin);
      FCLOSE(fpout);
936
      return (1);
G
Guy Schalnat 已提交
937
   }
938
#endif
A
Andreas Dilger 已提交
939
#endif
940

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
   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
   }

967
   pngtest_debug("Initializing input and output streams");
968
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
969
   png_init_io(read_ptr, fpin);
970
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
971
   png_init_io(write_ptr, fpout);
972
#  endif
973
#else
974
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
975
#  ifdef PNG_WRITE_SUPPORTED
976
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
977
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
978
      pngtest_flush);
979
#    else
980
      NULL);
981 982
#    endif
#  endif
983
#endif
984

985
   if (status_dots_requested == 1)
986
   {
987
#ifdef PNG_WRITE_SUPPORTED
988
      png_set_write_status_fn(write_ptr, write_row_callback);
989
#endif
990 991
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
992

993 994
   else
   {
995
#ifdef PNG_WRITE_SUPPORTED
996
      png_set_write_status_fn(write_ptr, NULL);
997
#endif
998
      png_set_read_status_fn(read_ptr, NULL);
999 1000
   }

1001
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1002
   {
1003
      int i;
1004

1005 1006
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
1007

1008
      png_set_read_user_transform_fn(read_ptr, count_filters);
1009 1010
   }
#endif
1011
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1012
   zero_samples = 0;
1013 1014
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
1015

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
#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
1026 1027
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
1028
#endif
1029
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1030
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1031
      NULL, 0);
1032
#endif
1033 1034
#endif

1035
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
1036
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
1037

1038 1039 1040 1041 1042 1043 1044 1045 1046
#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

1047
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
1048 1049
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
1050

A
Andreas Dilger 已提交
1051 1052 1053 1054 1055
      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,
            color_type, interlace_type, compression_type, filter_type);
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
#ifndef PNG_READ_INTERLACING_SUPPORTED
         /* num_pass will not be set below, set it here if the image is
          * interlaced: what happens is that write interlacing is *not* turned
          * on an the partial interlaced rows are written directly.
          */
         switch (interlace_type)
         {
            case PNG_INTERLACE_NONE:
               num_pass = 1;
               break;

            case PNG_INTERLACE_ADAM7:
               num_pass = 7;
                break;

            default:
                png_error(read_ptr, "invalid interlace type");
                /*NOT REACHED*/
         }
1075
#endif
A
Andreas Dilger 已提交
1076 1077
      }
   }
1078 1079
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1080
   {
1081
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1082
         blue_y;
1083

1084 1085
      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 已提交
1086
      {
1087 1088
         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 已提交
1089
      }
G
Guy Schalnat 已提交
1090
   }
A
Andreas Dilger 已提交
1091
#endif
1092
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1093
   {
1094
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1095

1096 1097
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1098 1099
   }
#endif
1100
#else /* Use floating point versions */
1101 1102
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1103 1104 1105
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1106

1107 1108 1109 1110 1111 1112 1113 1114
      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
1115
#ifdef PNG_gAMA_SUPPORTED
1116 1117 1118 1119 1120 1121 1122
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1123 1124
#endif /* Floating point */
#endif /* Fixed point */
1125
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1126
   {
1127
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1128
      png_bytep profile;
1129
      png_uint_32 proflen;
1130
      int compression_type;
A
Andreas Dilger 已提交
1131

1132 1133
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1134
      {
1135 1136
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1137
      }
G
Guy Schalnat 已提交
1138
   }
1139
#endif
1140
#ifdef PNG_sRGB_SUPPORTED
1141
   {
1142
      int intent;
1143 1144 1145 1146

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1147
#endif
1148 1149 1150 1151 1152 1153 1154
   {
      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);
   }
1155
#ifdef PNG_bKGD_SUPPORTED
1156 1157 1158 1159 1160 1161 1162 1163 1164
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1165
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1166
   {
A
Andreas Dilger 已提交
1167 1168 1169 1170
      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 已提交
1171
   }
A
Andreas Dilger 已提交
1172
#endif
1173
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1174
   {
1175
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1176
      int unit_type;
G
Guy Schalnat 已提交
1177

1178
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1179
          &unit_type))
A
Andreas Dilger 已提交
1180 1181 1182 1183 1184
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1185
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
   {
      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
1200
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1201 1202 1203 1204 1205 1206 1207 1208
   {
      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
1209
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1210
   {
1211
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1212

1213 1214
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1215
   }
1216
#endif
1217
#ifdef PNG_sCAL_SUPPORTED
1218 1219
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1220
   {
1221
      int unit;
1222
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1223

1224 1225
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1226
      {
1227
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1228 1229 1230
      }
   }
#else
1231
#ifdef PNG_FIXED_POINT_SUPPORTED
1232
   {
1233
      int unit;
1234
      png_charp scal_width, scal_height;
1235

1236 1237
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1238
      {
1239 1240
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1241 1242
      }
   }
G
Guy Schalnat 已提交
1243
#endif
1244 1245
#endif
#endif
1246
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1247 1248 1249 1250 1251 1252
   {
      png_textp text_ptr;
      int num_text;

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

1255 1256
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1257
         if (verbose)
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267
         {
            int i;

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

A
Andreas Dilger 已提交
1269 1270 1271 1272
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1273
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1274 1275 1276 1277 1278 1279
   {
      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);
1280
#ifdef PNG_TIME_RFC1123_SUPPORTED
1281
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1282
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1283 1284

         else
1285 1286 1287 1288
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1289

1290 1291
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1292
      }
A
Andreas Dilger 已提交
1293 1294
   }
#endif
1295
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1296
   {
1297
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1298
      int num_trans;
1299
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1300

1301
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1302
         &trans_color))
A
Andreas Dilger 已提交
1303
      {
1304
         int sample_max = (1 << bit_depth);
1305
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1306
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1307
             (int)trans_color->gray > sample_max) ||
1308
             (color_type == PNG_COLOR_TYPE_RGB &&
1309 1310 1311
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1312
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1313
               trans_color);
A
Andreas Dilger 已提交
1314 1315 1316
      }
   }
#endif
1317
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1318 1319
   {
      png_unknown_chunkp unknowns;
1320
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1321
         &unknowns);
1322

1323 1324 1325 1326
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1327
#if PNG_LIBPNG_VER < 10600
1328
         /* Copy the locations from the read_info_ptr.  The automatically
1329 1330
          * 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).
1331
          */
1332 1333 1334 1335 1336 1337 1338
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
1339 1340 1341
      }
   }
#endif
A
Andreas Dilger 已提交
1342

1343
#ifdef PNG_WRITE_SUPPORTED
1344
   pngtest_debug("Writing info struct");
1345

1346 1347 1348 1349
   /* 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);
1350

1351
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1352

1353
   png_write_info(write_ptr, write_info_ptr);
1354

1355
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1356
#endif
A
Andreas Dilger 已提交
1357

1358
#ifdef SINGLE_ROWBUF_ALLOC
1359
   pngtest_debug("Allocating row buffer...");
1360
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1361
      png_get_rowbytes(read_ptr, read_info_ptr));
1362

1363
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1364
#endif /* SINGLE_ROWBUF_ALLOC */
1365
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1366

1367
#ifdef PNG_READ_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
1368
   num_pass = png_set_interlace_handling(read_ptr);
1369 1370
   if (png_set_interlace_handling(write_ptr) != num_pass)
      png_error(write_ptr, "png_set_interlace_handling: inconsistent num_pass");
1371
#endif
A
Andreas Dilger 已提交
1372

1373 1374 1375 1376 1377
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1378 1379
   for (pass = 0; pass < num_pass; pass++)
   {
1380
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1381 1382
      for (y = 0; y < height; y++)
      {
1383
#ifndef SINGLE_ROWBUF_ALLOC
1384
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1385 1386
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1387

1388
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1389
            png_get_rowbytes(read_ptr, read_info_ptr));
1390

1391
#endif /* !SINGLE_ROWBUF_ALLOC */
1392
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1393 1394

#ifdef PNG_WRITE_SUPPORTED
1395 1396 1397 1398 1399
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1400
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1401 1402 1403 1404 1405
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1406 1407 1408
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1409
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1410
         png_free(read_ptr, row_buf);
1411
         row_buf = NULL;
1412
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1413 1414 1415
      }
   }

1416 1417 1418 1419 1420 1421 1422
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
#  ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
      png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
#  endif
#  ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
      png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
#  endif
1423 1424
#endif

1425
   pngtest_debug("Reading and writing end_info data");
1426

A
Andreas Dilger 已提交
1427
   png_read_end(read_ptr, end_info_ptr);
1428
#ifdef PNG_TEXT_SUPPORTED
1429 1430 1431 1432 1433 1434
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1435
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450

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

1451 1452 1453 1454
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1455
#ifdef PNG_tIME_SUPPORTED
1456 1457 1458 1459 1460 1461
   {
      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);
1462
#ifdef PNG_TIME_RFC1123_SUPPORTED
1463
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1464
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1465 1466

         else
1467 1468 1469 1470
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1471

1472 1473 1474 1475
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1476
#endif
1477
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1478 1479
   {
      png_unknown_chunkp unknowns;
1480
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1481
         &unknowns);
1482

1483 1484 1485 1486
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1487
#if PNG_LIBPNG_VER < 10600
1488
         /* Copy the locations from the read_info_ptr.  The automatically
1489 1490
          * 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).
1491
          */
1492 1493 1494 1495 1496 1497 1498
         {
            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
1499 1500
      }
   }
1501
#endif
1502

1503
#ifdef PNG_WRITE_SUPPORTED
1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
#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);

1520
   png_write_end(write_ptr, write_end_info_ptr);
1521
#endif
1522

1523
#ifdef PNG_EASY_ACCESS_SUPPORTED
1524
   if (verbose)
1525 1526 1527 1528
   {
      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);
1529
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1530
         (unsigned long)iwidth, (unsigned long)iheight);
1531 1532
   }
#endif
G
Guy Schalnat 已提交
1533

1534
   pngtest_debug("Destroying data structs");
1535
#ifdef SINGLE_ROWBUF_ALLOC
1536
   pngtest_debug("destroying row_buf for read_ptr");
1537
   png_free(read_ptr, row_buf);
1538
   row_buf = NULL;
1539
#endif /* SINGLE_ROWBUF_ALLOC */
1540
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1541
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1542
#ifdef PNG_WRITE_SUPPORTED
1543
   pngtest_debug("destroying write_end_info_ptr");
1544
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1545
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1546
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1547
#endif
1548
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1549

1550 1551
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1552

1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
   /* 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);
   }

1587
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1588
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1589
   {
G
Guy Schalnat 已提交
1590
      fprintf(STDERR, "Could not find file %s\n", inname);
1591
      return (1);
G
Guy Schalnat 已提交
1592 1593
   }

A
Andreas Dilger 已提交
1594
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1595
   {
G
Guy Schalnat 已提交
1596
      fprintf(STDERR, "Could not find file %s\n", outname);
1597
      FCLOSE(fpin);
1598
      return (1);
G
Guy Schalnat 已提交
1599
   }
A
Andreas Dilger 已提交
1600

1601
#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
1602
   if (interlace_preserved) /* else the files will be changed */
G
Guy Schalnat 已提交
1603
   {
1604
      for (;;)
1605
      {
1606
         static int wrote_question = 0;
1607 1608 1609 1610 1611
         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);
1612

1613
         if (num_in != num_out)
1614
         {
1615 1616
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);
1617

1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629
            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;
            }
1630

1631 1632
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1633

1634 1635
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1636

1637 1638 1639
            else
              return (0);
         }
1640

1641 1642
         if (!num_in)
            break;
1643

1644
         if (memcmp(inbuf, outbuf, num_in))
1645
         {
1646 1647 1648 1649 1650 1651
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1652
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1653 1654 1655 1656 1657 1658 1659 1660
                    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;
            }
1661

1662 1663
            FCLOSE(fpin);
            FCLOSE(fpout);
1664

1665 1666 1667 1668 1669 1670 1671
            /* 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);
1672

1673 1674 1675
            else
              return (0);
         }
G
Guy Schalnat 已提交
1676 1677
      }
   }
1678
#endif /* PNG_WRITE_SUPPORTED */
G
Guy Schalnat 已提交
1679

1680 1681
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1682

1683
   return (0);
G
Guy Schalnat 已提交
1684
}
G
Guy Schalnat 已提交
1685

1686
/* Input and output filenames */
1687
#ifdef RISCOS
1688 1689
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1690
#else
1691 1692
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1693 1694 1695 1696 1697 1698 1699 1700
#endif

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

1701
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1702
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1703
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1704
   /* Show the version of libpng used in building the library */
1705 1706
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1707
      png_get_header_version(NULL));
1708

1709
   /* Show the version of libpng used in building the application */
1710
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1711
      PNG_HEADER_VERSION_STRING);
1712 1713

   /* Do some consistency checking on the memory allocation settings, I'm
1714 1715 1716 1717
    * 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
    */
1718
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1719
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1720
#endif
1721
   /* I think the following can happen. */
1722
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1723
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1724
#endif
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736

   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)
   {
1737
      if (strcmp(argv[1], "-m") == 0)
1738
      {
1739
         multiple = 1;
1740 1741
         status_dots_requested = 0;
      }
1742

1743 1744 1745 1746 1747
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1748
         status_dots_requested = 1;
1749
      }
1750

1751 1752 1753
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1754
         status_dots_requested = 1;
1755 1756
         inname = argv[2];
      }
1757

1758 1759 1760 1761 1762 1763
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
         relaxed = 0;
      }

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

1776
      else
1777
      {
1778
         inname = argv[1];
1779 1780
         status_dots_requested = 0;
      }
1781 1782
   }

1783 1784
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1785

1786
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1787
   {
1788 1789
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1790
        argv[0], argv[0]);
1791 1792 1793 1794
     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);
1795 1796 1797 1798 1799 1800
     exit(1);
   }

   if (multiple)
   {
      int i;
1801
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1802 1803
      int allocation_now = current_allocation;
#endif
1804
      for (i=2; i<argc; ++i)
1805
      {
1806
         int kerror;
1807
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1808
         kerror = test_one_file(argv[i], outname);
1809
         if (kerror == 0)
1810
         {
1811 1812 1813
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1814
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1815
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1816
               (unsigned long)zero_samples);
1817
#else
1818
            fprintf(STDERR, " PASS\n");
1819
#endif
1820
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1821 1822
            for (k = 0; k<256; k++)
               if (filters_used[k])
1823
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1824
                     k, (unsigned long)filters_used[k]);
1825
#endif
1826
#ifdef PNG_TIME_RFC1123_SUPPORTED
1827 1828
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1829

1830 1831 1832
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1833

1834 1835
         else
         {
1836 1837
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1838
         }
1839
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1840 1841
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1842
               current_allocation - allocation_now);
1843

1844 1845
         if (current_allocation != 0)
         {
1846 1847 1848 1849
            memory_infop pinfo = pinformation;

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

1851 1852
            while (pinfo != NULL)
            {
1853
               fprintf(STDERR, " %lu bytes at %x\n",
1854
                 (unsigned long)pinfo->size,
1855
                 (unsigned int)pinfo->pointer);
1856
               pinfo = pinfo->next;
1857
            }
1858
         }
1859 1860
#endif
      }
1861
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1862
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1863
            current_allocation);
1864
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1865
            maximum_allocation);
1866 1867 1868 1869
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1870
#endif
1871
   }
1872

1873 1874
   else
   {
1875
      int i;
1876
      for (i = 0; i<3; ++i)
1877
      {
1878
         int kerror;
1879
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1880 1881
         int allocation_now = current_allocation;
#endif
1882 1883 1884 1885 1886 1887
         if (i == 1)
            status_dots_requested = 1;

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

1888
         if (i == 0 || verbose == 1 || ierror != 0)
1889
            fprintf(STDERR, "\n Testing %s:", inname);
1890

1891
         kerror = test_one_file(inname, outname);
1892

1893
         if (kerror == 0)
1894
         {
1895
            if (verbose == 1 || i == 2)
1896
            {
1897
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1898
                int k;
1899
#endif
1900
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1901
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1902
                   (unsigned long)zero_samples);
1903 1904 1905
#else
                fprintf(STDERR, " PASS\n");
#endif
1906
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1907 1908
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1909
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1910
                         k, (unsigned long)filters_used[k]);
1911
#endif
1912
#ifdef PNG_TIME_RFC1123_SUPPORTED
1913 1914
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1915 1916
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1917
         }
1918

1919 1920
         else
         {
1921
            if (verbose == 0 && i != 2)
1922
               fprintf(STDERR, "\n Testing %s:", inname);
1923

1924 1925
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1926
         }
1927
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1928 1929
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1930
               current_allocation - allocation_now);
1931

1932 1933
         if (current_allocation != 0)
         {
1934
             memory_infop pinfo = pinformation;
1935

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

1939 1940
             while (pinfo != NULL)
             {
1941 1942
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1943 1944 1945 1946
                pinfo = pinfo->next;
             }
          }
#endif
1947
       }
1948
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1949
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1950
          current_allocation);
1951
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1952
          maximum_allocation);
1953 1954 1955 1956
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1957
#endif
1958 1959
   }

1960 1961 1962 1963
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1964
   fprintf(STDERR, " CPU time used = %.3f seconds",
1965
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1966
   fprintf(STDERR, " (decoding %.3f,\n",
1967
      t_decode/(float)CLOCKS_PER_SEC);
1968
   fprintf(STDERR, "        encoding %.3f ,",
1969
      t_encode/(float)CLOCKS_PER_SEC);
1970
   fprintf(STDERR, " other %.3f seconds)\n\n",
1971 1972 1973
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1974
   if (ierror == 0)
1975
      fprintf(STDERR, " libpng passes test\n");
1976

1977
   else
1978
      fprintf(STDERR, " libpng FAILS test\n");
1979

1980
   return (int)(ierror != 0);
1981
}
1982 1983 1984 1985 1986 1987
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
1988
   /* And skip this test */
1989
   return PNG_LIBPNG_VER < 10600 ? 0 : 77;
1990 1991
}
#endif
1992

1993
/* Generate a compiler error if there is an old png.h in the search path. */
1994
typedef png_libpng_version_1_6_10rc04 Your_png_h_is_not_version_1_6_10rc04;