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

34 35
#define _POSIX_SOURCE 1

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

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

44
#include "png.h"
45

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/* 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
 */
#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 &&\
   defined PNG_READ_zTXt_SUPPORTED

63
#include "zlib.h"
64 65 66 67
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
68
#define FCLOSE(file) fclose(file)
69

70
#ifndef PNG_STDIO_SUPPORTED
71
typedef FILE                * png_FILE_p;
72 73
#endif

74
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
75
#ifndef PNG_DEBUG
76 77 78
#  define PNG_DEBUG 0
#endif

79 80 81 82 83 84 85 86 87
#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
88

89
#if !PNG_DEBUG
90
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
91
#endif
A
Andreas Dilger 已提交
92

93 94 95 96
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

97
#ifndef PNG_FLOATING_POINT_SUPPORTED
98 99 100
#undef PNGTEST_TIMING
#endif

101 102 103 104 105
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

106
#ifdef PNG_TIME_RFC1123_SUPPORTED
107
#define PNG_tIME_STRING_LENGTH 29
108
static int tIME_chunk_present = 0;
109
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
110 111
#endif

112
static int verbose = 0;
113
static int strict = 0;
114 115 116 117
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 */
118
static int wrote_question = 0;
119

G
Guy Schalnat 已提交
120 121 122 123
#ifdef __TURBOC__
#include <mem.h>
#endif

124 125 126 127 128
/* 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

129 130 131 132 133 134 135 136 137 138 139
/* 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))

140
/* Example of using row callbacks to make a simple progress meter */
141 142 143
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
144

145
static void PNGCBAPI
146
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
147
{
148 149
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
150

151 152 153 154 155 156
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
157

158
   status_dots--;
159

160 161 162 163 164
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
165

166
   fprintf(stdout, "r");
167
}
168

169 170
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
171
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
172
{
173 174
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
175

176
   fprintf(stdout, "w");
177
}
178
#endif
179 180


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

195
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
196
/* Example of using user transform callback (we don't transform anything,
197 198
 * but merely count the zero samples)
 */
199

200
static png_uint_32 zero_samples;
201

202
static void PNGCBAPI
203
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
204 205
{
   png_bytep dp = data;
206 207
   if (png_ptr == NULL)
      return;
208

209
   /* Contents of row_info:
210 211 212 213 214 215 216 217
    *  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)
    */

218
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
219

220
    if (row_info->color_type == 0 || row_info->color_type == 3)
221
    {
222
       int pos = 0;
223
       png_uint_32 n, nstop;
224

225
       for (n = 0, nstop=row_info->width; n<nstop; n++)
226
       {
227
          if (row_info->bit_depth == 1)
228
          {
229 230
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
231

232
             if (pos == 8)
233
             {
234
                pos = 0;
235 236
                dp++;
             }
237
          }
238

239
          if (row_info->bit_depth == 2)
240
          {
241 242
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
243

244
             if (pos == 8)
245
             {
246
                pos = 0;
247 248
                dp++;
             }
249
          }
250

251
          if (row_info->bit_depth == 4)
252
          {
253 254
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
255

256
             if (pos == 8)
257
             {
258
                pos = 0;
259 260
                dp++;
             }
261
          }
262

263
          if (row_info->bit_depth == 8)
264 265
             if (*dp++ == 0)
                zero_samples++;
266

267
          if (row_info->bit_depth == 16)
268
          {
269 270
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
271 272 273 274
             dp+=2;
          }
       }
    }
275
    else /* Other color types */
276
    {
277
       png_uint_32 n, nstop;
278 279
       int channel;
       int color_channels = row_info->channels;
280
       if (row_info->color_type > 3)color_channels--;
281

282
       for (n = 0, nstop=row_info->width; n<nstop; n++)
283 284 285
       {
          for (channel = 0; channel < color_channels; channel++)
          {
286
             if (row_info->bit_depth == 8)
287 288
                if (*dp++ == 0)
                   zero_samples++;
289

290
             if (row_info->bit_depth == 16)
291
             {
292 293
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
294

295 296 297
                dp+=2;
             }
          }
298
          if (row_info->color_type > 3)
299 300
          {
             dp++;
301 302
             if (row_info->bit_depth == 16)
                dp++;
303 304 305 306
          }
       }
    }
}
307
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
308

309
#ifndef PNG_STDIO_SUPPORTED
310
/* START of code to validate stdio-free compilation */
311 312 313 314 315 316 317
/* 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.
 */
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 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
#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

361
static void PNGCBAPI
362
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
363
{
364 365
   png_size_t check = 0;
   png_voidp io_ptr;
366 367 368 369

   /* 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.
    */
370 371 372 373 374
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
375

376 377
   if (check != length)
   {
378
      png_error(png_ptr, "Read Error");
379
   }
380 381 382 383

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

386
#ifdef PNG_WRITE_FLUSH_SUPPORTED
387
static void PNGCBAPI
388
pngtest_flush(png_structp png_ptr)
389
{
390
   /* Do nothing; fflush() is said to be just a waste of energy. */
391
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
392 393
}
#endif
G
Guy Schalnat 已提交
394

395
/* This is the function that does the actual writing of data.  If you are
396 397 398 399
 * 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.
 */
400
static void PNGCBAPI
401
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
402
{
403
   png_size_t check;
404

405
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
406

407 408 409 410
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
411 412 413 414

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
415
}
416
#endif /* !PNG_STDIO_SUPPORTED */
417 418 419 420 421 422

/* 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.
 */
423 424 425 426 427
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

428
static void PNGCBAPI
429
pngtest_warning(png_structp png_ptr, png_const_charp message)
430 431
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
432 433
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
434

435
   ++warning_count;
436

437 438 439 440
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
441 442 443 444 445 446 447
}

/* 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().
 */
448
static void PNGCBAPI
449
pngtest_error(png_structp png_ptr, png_const_charp message)
450
{
451 452
   ++error_count;

453
   pngtest_warning(png_ptr, message);
454
   /* We can return because png_error calls the default handler, which is
455 456
    * actually OK in this case.
    */
457
}
458

459 460
/* END of code to validate stdio-free compilation */

461
/* START of code to validate memory allocation and deallocation */
462
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
463 464

/* Allocate memory.  For reasonable files, size should never exceed
465 466 467 468 469 470 471 472
 * 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.
 */
473 474
typedef struct memory_information
{
475
   png_alloc_size_t          size;
476
   png_voidp                 pointer;
477
   struct memory_information *next;
478
} memory_information;
479
typedef memory_information *memory_infop;
480 481 482 483

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
484 485
static int total_allocation = 0;
static int num_allocations = 0;
486

487 488 489
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));
490 491

png_voidp
492
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
493
{
494

495
   /* png_malloc has already tested for NULL; png_create_struct calls
496 497
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
498

499
   if (size == 0)
500
      return (NULL);
501 502 503 504

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
505
      /* Disable malloc_fn and free_fn */
506
      memory_infop pinfo;
507
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
508
      pinfo = (memory_infop)png_malloc(png_ptr,
509
         (sizeof *pinfo));
510 511
      pinfo->size = size;
      current_allocation += size;
512 513
      total_allocation += size;
      num_allocations ++;
514

515 516
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
517

518
      pinfo->pointer = png_malloc(png_ptr, size);
519
      /* Restore malloc_fn and free_fn */
520

521 522
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
523

524 525 526 527
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
528
         png_error(png_ptr,
529
           "out of memory in pngtest->png_debug_malloc");
530
      }
531

532 533 534
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
535
      memset(pinfo->pointer, 0xdd, pinfo->size);
536

537
      if (verbose)
538
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
539
            pinfo->pointer);
540

541
      return (png_voidp)(pinfo->pointer);
542 543 544 545
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
546
void PNGCBAPI
547
png_debug_free(png_structp png_ptr, png_voidp ptr)
548 549
{
   if (png_ptr == NULL)
550
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
551

552 553
   if (ptr == 0)
   {
554 555 556 557 558 559 560 561
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
562
      memory_infop *ppinfo = &pinformation;
563

564 565
      for (;;)
      {
566
         memory_infop pinfo = *ppinfo;
567

568 569
         if (pinfo->pointer == ptr)
         {
570 571 572 573 574
            *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
575
               the memory that is to be freed. */
576
            memset(ptr, 0x55, pinfo->size);
577
            png_free_default(png_ptr, pinfo);
578
            pinfo = NULL;
579 580
            break;
         }
581

582 583
         if (pinfo->next == NULL)
         {
584
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
585 586
            break;
         }
587

588 589 590 591 592
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
593
   if (verbose)
594
      printf("Freeing %p\n", ptr);
595

596
   png_free_default(png_ptr, ptr);
597
   ptr = NULL;
598
}
599
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
600 601
/* END of code to test memory allocation/deallocation */

602

603
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
604 605
/* Demonstration of user chunk support of the sTER and vpAg chunks */

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

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
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
625

626 627 628 629 630 631 632 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
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 */
}
661

662
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
663 664
   png_unknown_chunkp chunk)
{
665 666 667 668 669
   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");
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689

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

691 692
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
693

694 695 696 697 698 699 700 701
         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 */
702 703 704 705 706 707 708 709 710 711 712
      }

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

713 714
   if (!set_location(png_ptr, my_user_chunk_data, have_vpAg))
      return (0);  /* duplicate vpAg */
715

716 717 718
   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];
719 720

   return (1);
721 722 723 724 725 726 727 728 729 730
}

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

732
   png_write_chunk(write_ptr, png_sTER, &user_chunk_data.sTER_mode, 1);
733
}
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

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

   png_byte vpag_chunk_data[9];

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

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

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

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

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

780 781 782 783 784 785 786 787 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
/* 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 */

819
/* Test one file */
820
static int
821
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
822
{
823 824
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
825
   pngtest_error_parameters error_parameters;
826 827 828 829 830 831 832 833 834 835 836
   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 已提交
837
   png_bytep row_buf;
G
Guy Schalnat 已提交
838
   png_uint_32 y;
A
Andreas Dilger 已提交
839 840 841
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
842

843
   row_buf = NULL;
844
   error_parameters.file_name = inname;
G
Guy Schalnat 已提交
845

A
Andreas Dilger 已提交
846
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
847 848
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
849
      return (1);
G
Guy Schalnat 已提交
850 851
   }

A
Andreas Dilger 已提交
852
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
853
   {
G
Guy Schalnat 已提交
854
      fprintf(STDERR, "Could not open output file %s\n", outname);
855
      FCLOSE(fpin);
856
      return (1);
G
Guy Schalnat 已提交
857 858
   }

859
   pngtest_debug("Allocating read and write structures");
860
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
861 862
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
863
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
864
#else
865 866
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
867
#endif
868 869
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
870

871
#ifdef PNG_WRITE_SUPPORTED
872
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
873 874 875
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
876
#else
877 878
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
879
#endif
880 881
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
882
#endif
883
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
884
   read_info_ptr = png_create_info_struct(read_ptr);
885
   end_info_ptr = png_create_info_struct(read_ptr);
886 887
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
888
   write_end_info_ptr = png_create_info_struct(write_ptr);
889
#endif
G
Guy Schalnat 已提交
890

891 892 893 894 895 896
#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

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

914
#ifdef PNG_WRITE_SUPPORTED
915
   pngtest_debug("Setting jmpbuf for write struct");
916

917
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
918
   {
919
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
920
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
921
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
922
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
923
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
924
#endif
925 926
      FCLOSE(fpin);
      FCLOSE(fpout);
927
      return (1);
G
Guy Schalnat 已提交
928
   }
929
#endif
A
Andreas Dilger 已提交
930
#endif
931

932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
   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
   }

958
   pngtest_debug("Initializing input and output streams");
959
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
960
   png_init_io(read_ptr, fpin);
961
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
962
   png_init_io(write_ptr, fpout);
963
#  endif
964
#else
965
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
966
#  ifdef PNG_WRITE_SUPPORTED
967
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
968
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
969
      pngtest_flush);
970
#    else
971
      NULL);
972 973
#    endif
#  endif
974
#endif
975

976
   if (status_dots_requested == 1)
977
   {
978
#ifdef PNG_WRITE_SUPPORTED
979
      png_set_write_status_fn(write_ptr, write_row_callback);
980
#endif
981 982
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
983

984 985
   else
   {
986
#ifdef PNG_WRITE_SUPPORTED
987
      png_set_write_status_fn(write_ptr, NULL);
988
#endif
989
      png_set_read_status_fn(read_ptr, NULL);
990 991
   }

992
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
993
   {
994
      int i;
995

996 997
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
998

999
      png_set_read_user_transform_fn(read_ptr, count_filters);
1000 1001
   }
#endif
1002
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1003
   zero_samples = 0;
1004 1005
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
1006

1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
#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
1017 1018
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
1019
#endif
1020
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1021
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1022
      NULL, 0);
1023
#endif
1024 1025
#endif

1026
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
1027
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
1028

1029 1030 1031 1032 1033 1034 1035 1036 1037
#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

1038
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
1039 1040
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
1041

A
Andreas Dilger 已提交
1042 1043 1044 1045
      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,
1046
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
1047
            color_type, interlace_type, compression_type, filter_type);
1048 1049 1050
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
1051 1052
      }
   }
1053 1054
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1055
   {
1056
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1057
         blue_y;
1058

1059 1060
      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 已提交
1061
      {
1062 1063
         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 已提交
1064
      }
G
Guy Schalnat 已提交
1065
   }
A
Andreas Dilger 已提交
1066
#endif
1067
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1068
   {
1069
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1070

1071 1072
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1073 1074
   }
#endif
1075
#else /* Use floating point versions */
1076 1077
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1078 1079 1080
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1081

1082 1083 1084 1085 1086 1087 1088 1089
      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
1090
#ifdef PNG_gAMA_SUPPORTED
1091 1092 1093 1094 1095 1096 1097
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1098 1099
#endif /* Floating point */
#endif /* Fixed point */
1100
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1101
   {
1102
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1103
      png_bytep profile;
1104
      png_uint_32 proflen;
1105
      int compression_type;
A
Andreas Dilger 已提交
1106

1107 1108
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1109
      {
1110 1111
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1112
      }
G
Guy Schalnat 已提交
1113
   }
1114
#endif
1115
#ifdef PNG_sRGB_SUPPORTED
1116
   {
1117
      int intent;
1118 1119 1120 1121

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1122
#endif
1123 1124 1125 1126 1127 1128 1129
   {
      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);
   }
1130
#ifdef PNG_bKGD_SUPPORTED
1131 1132 1133 1134 1135 1136 1137 1138 1139
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1140
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1141
   {
A
Andreas Dilger 已提交
1142 1143 1144 1145
      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 已提交
1146
   }
A
Andreas Dilger 已提交
1147
#endif
1148
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1149
   {
1150
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1151
      int unit_type;
G
Guy Schalnat 已提交
1152

1153
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1154
          &unit_type))
A
Andreas Dilger 已提交
1155 1156 1157 1158 1159
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1160
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
   {
      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
1175
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1176 1177 1178 1179 1180 1181 1182 1183
   {
      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
1184
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1185
   {
1186
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1187

1188 1189
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1190
   }
1191
#endif
1192
#ifdef PNG_sCAL_SUPPORTED
1193 1194
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1195
   {
1196
      int unit;
1197
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1198

1199 1200
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1201
      {
1202
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1203 1204 1205
      }
   }
#else
1206
#ifdef PNG_FIXED_POINT_SUPPORTED
1207
   {
1208
      int unit;
1209
      png_charp scal_width, scal_height;
1210

1211 1212
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1213
      {
1214 1215
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1216 1217
      }
   }
G
Guy Schalnat 已提交
1218
#endif
1219 1220
#endif
#endif
1221
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1222 1223 1224 1225 1226 1227
   {
      png_textp text_ptr;
      int num_text;

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

1230 1231
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1232
         if (verbose)
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
         {
            int i;

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

A
Andreas Dilger 已提交
1244 1245 1246 1247
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1248
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1249 1250 1251 1252 1253 1254
   {
      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);
1255
#ifdef PNG_TIME_RFC1123_SUPPORTED
1256
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1257
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1258 1259

         else
1260 1261 1262 1263
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1264

1265 1266
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1267
      }
A
Andreas Dilger 已提交
1268 1269
   }
#endif
1270
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1271
   {
1272
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1273
      int num_trans;
1274
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1275

1276
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1277
         &trans_color))
A
Andreas Dilger 已提交
1278
      {
1279
         int sample_max = (1 << bit_depth);
1280
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1281
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1282
             (int)trans_color->gray > sample_max) ||
1283
             (color_type == PNG_COLOR_TYPE_RGB &&
1284 1285 1286
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1287
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1288
               trans_color);
A
Andreas Dilger 已提交
1289 1290 1291
      }
   }
#endif
1292
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1293 1294
   {
      png_unknown_chunkp unknowns;
1295
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1296
         &unknowns);
1297

1298 1299 1300 1301
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1302
#if PNG_LIBPNG_VER < 10600
1303
         /* Copy the locations from the read_info_ptr.  The automatically
1304 1305
          * 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).
1306
          */
1307 1308 1309 1310 1311 1312 1313
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
1314 1315 1316
      }
   }
#endif
A
Andreas Dilger 已提交
1317

1318
#ifdef PNG_WRITE_SUPPORTED
1319
   pngtest_debug("Writing info struct");
1320

1321 1322 1323 1324
   /* 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);
1325

1326
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1327

1328
   png_write_info(write_ptr, write_info_ptr);
1329

1330
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1331
#endif
A
Andreas Dilger 已提交
1332

1333
#ifdef SINGLE_ROWBUF_ALLOC
1334
   pngtest_debug("Allocating row buffer...");
1335
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1336
      png_get_rowbytes(read_ptr, read_info_ptr));
1337

1338
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1339
#endif /* SINGLE_ROWBUF_ALLOC */
1340
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1341

1342 1343
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1344
   num_pass = png_set_interlace_handling(read_ptr);
1345
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1346
   png_set_interlace_handling(write_ptr);
1347
#  endif
1348
#else
1349
   num_pass = 1;
1350
#endif
A
Andreas Dilger 已提交
1351

1352 1353 1354 1355 1356
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1357 1358
   for (pass = 0; pass < num_pass; pass++)
   {
1359
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1360 1361
      for (y = 0; y < height; y++)
      {
1362
#ifndef SINGLE_ROWBUF_ALLOC
1363
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1364 1365
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1366

1367
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1368
            png_get_rowbytes(read_ptr, read_info_ptr));
1369

1370
#endif /* !SINGLE_ROWBUF_ALLOC */
1371
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1372 1373

#ifdef PNG_WRITE_SUPPORTED
1374 1375 1376 1377 1378
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1379
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1380 1381 1382 1383 1384
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1385 1386 1387
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1388
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1389
         png_free(read_ptr, row_buf);
1390
         row_buf = NULL;
1391
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1392 1393 1394
      }
   }

1395 1396 1397 1398 1399 1400 1401
#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
1402 1403
#endif

1404
   pngtest_debug("Reading and writing end_info data");
1405

A
Andreas Dilger 已提交
1406
   png_read_end(read_ptr, end_info_ptr);
1407
#ifdef PNG_TEXT_SUPPORTED
1408 1409 1410 1411 1412 1413
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1414
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429

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

1430 1431 1432 1433
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1434
#ifdef PNG_tIME_SUPPORTED
1435 1436 1437 1438 1439 1440
   {
      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);
1441
#ifdef PNG_TIME_RFC1123_SUPPORTED
1442
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1443
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1444 1445

         else
1446 1447 1448 1449
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1450

1451 1452 1453 1454
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1455
#endif
1456
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1457 1458
   {
      png_unknown_chunkp unknowns;
1459
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1460
         &unknowns);
1461

1462 1463 1464 1465
      if (num_unknowns)
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1466
#if PNG_LIBPNG_VER < 10600
1467
         /* Copy the locations from the read_info_ptr.  The automatically
1468 1469
          * 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).
1470
          */
1471 1472 1473 1474 1475 1476 1477
         {
            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
1478 1479
      }
   }
1480
#endif
1481

1482
#ifdef PNG_WRITE_SUPPORTED
1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
#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);

1499
   png_write_end(write_ptr, write_end_info_ptr);
1500
#endif
1501

1502
#ifdef PNG_EASY_ACCESS_SUPPORTED
1503
   if (verbose)
1504 1505 1506 1507
   {
      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);
1508
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1509
         (unsigned long)iwidth, (unsigned long)iheight);
1510 1511
   }
#endif
G
Guy Schalnat 已提交
1512

1513
   pngtest_debug("Destroying data structs");
1514
#ifdef SINGLE_ROWBUF_ALLOC
1515
   pngtest_debug("destroying row_buf for read_ptr");
1516
   png_free(read_ptr, row_buf);
1517
   row_buf = NULL;
1518
#endif /* SINGLE_ROWBUF_ALLOC */
1519
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1520
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1521
#ifdef PNG_WRITE_SUPPORTED
1522
   pngtest_debug("destroying write_end_info_ptr");
1523
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1524
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1525
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1526
#endif
1527
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1528

1529 1530
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1531

1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
   /* 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);
   }

1566
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1567
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1568
   {
G
Guy Schalnat 已提交
1569
      fprintf(STDERR, "Could not find file %s\n", inname);
1570
      return (1);
G
Guy Schalnat 已提交
1571 1572
   }

A
Andreas Dilger 已提交
1573
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1574
   {
G
Guy Schalnat 已提交
1575
      fprintf(STDERR, "Could not find file %s\n", outname);
1576
      FCLOSE(fpin);
1577
      return (1);
G
Guy Schalnat 已提交
1578
   }
A
Andreas Dilger 已提交
1579

1580
#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
G
Guy Schalnat 已提交
1581
   {
1582

1583
      for (;;)
1584
      {
1585 1586 1587 1588 1589 1590
         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);
1591

1592
         if (num_in != num_out)
1593
         {
1594 1595
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);
1596

1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608
            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;
            }
1609

1610 1611
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1612

1613 1614
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1615

1616 1617 1618
            else
              return (0);
         }
1619

1620 1621
         if (!num_in)
            break;
1622

1623
         if (memcmp(inbuf, outbuf, num_in))
1624
         {
1625 1626 1627 1628 1629 1630
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1631
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1632 1633 1634 1635 1636 1637 1638 1639
                    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;
            }
1640

1641 1642
            FCLOSE(fpin);
            FCLOSE(fpout);
1643

1644 1645 1646 1647 1648 1649 1650
            /* 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);
1651

1652 1653 1654
            else
              return (0);
         }
G
Guy Schalnat 已提交
1655 1656
      }
   }
1657
#endif /* PNG_WRITE_SUPPORTED */
G
Guy Schalnat 已提交
1658

1659 1660
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1661

1662
   return (0);
G
Guy Schalnat 已提交
1663
}
G
Guy Schalnat 已提交
1664

1665
/* Input and output filenames */
1666
#ifdef RISCOS
1667 1668
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1669
#else
1670 1671
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1672 1673 1674 1675 1676 1677 1678 1679
#endif

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

1680
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1681
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1682
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1683
   /* Show the version of libpng used in building the library */
1684 1685
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1686
      png_get_header_version(NULL));
1687

1688
   /* Show the version of libpng used in building the application */
1689
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1690
      PNG_HEADER_VERSION_STRING);
1691 1692

   /* Do some consistency checking on the memory allocation settings, I'm
1693 1694 1695 1696
    * 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
    */
1697
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1698
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1699
#endif
1700
   /* I think the following can happen. */
1701
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1702
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1703
#endif
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715

   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)
   {
1716
      if (strcmp(argv[1], "-m") == 0)
1717
      {
1718
         multiple = 1;
1719 1720
         status_dots_requested = 0;
      }
1721

1722 1723 1724 1725 1726
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1727
         status_dots_requested = 1;
1728
      }
1729

1730 1731 1732
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1733
         status_dots_requested = 1;
1734 1735
         inname = argv[2];
      }
1736

1737 1738 1739 1740 1741 1742
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
         relaxed = 0;
      }

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

1755
      else
1756
      {
1757
         inname = argv[1];
1758 1759
         status_dots_requested = 0;
      }
1760 1761
   }

1762 1763
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1764

1765
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1766
   {
1767 1768
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1769
        argv[0], argv[0]);
1770 1771 1772 1773
     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);
1774 1775 1776 1777 1778 1779
     exit(1);
   }

   if (multiple)
   {
      int i;
1780
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1781 1782
      int allocation_now = current_allocation;
#endif
1783
      for (i=2; i<argc; ++i)
1784
      {
1785
         int kerror;
1786
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1787
         kerror = test_one_file(argv[i], outname);
1788
         if (kerror == 0)
1789
         {
1790 1791 1792
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1793
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1794
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1795
               (unsigned long)zero_samples);
1796
#else
1797
            fprintf(STDERR, " PASS\n");
1798
#endif
1799
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1800 1801
            for (k = 0; k<256; k++)
               if (filters_used[k])
1802
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1803
                     k, (unsigned long)filters_used[k]);
1804
#endif
1805
#ifdef PNG_TIME_RFC1123_SUPPORTED
1806 1807
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1808

1809 1810 1811
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1812

1813 1814
         else
         {
1815 1816
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1817
         }
1818
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1819 1820
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1821
               current_allocation - allocation_now);
1822

1823 1824
         if (current_allocation != 0)
         {
1825 1826 1827 1828
            memory_infop pinfo = pinformation;

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

1830 1831
            while (pinfo != NULL)
            {
1832
               fprintf(STDERR, " %lu bytes at %x\n",
1833
                 (unsigned long)pinfo->size,
1834
                 (unsigned int)pinfo->pointer);
1835
               pinfo = pinfo->next;
1836
            }
1837
         }
1838 1839
#endif
      }
1840
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1841
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1842
            current_allocation);
1843
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1844
            maximum_allocation);
1845 1846 1847 1848
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1849
#endif
1850
   }
1851

1852 1853
   else
   {
1854
      int i;
1855
      for (i = 0; i<3; ++i)
1856
      {
1857
         int kerror;
1858
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1859 1860
         int allocation_now = current_allocation;
#endif
1861 1862 1863 1864 1865 1866
         if (i == 1)
            status_dots_requested = 1;

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

1867
         if (i == 0 || verbose == 1 || ierror != 0)
1868
            fprintf(STDERR, "\n Testing %s:", inname);
1869

1870
         kerror = test_one_file(inname, outname);
1871

1872
         if (kerror == 0)
1873
         {
1874
            if (verbose == 1 || i == 2)
1875
            {
1876
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1877
                int k;
1878
#endif
1879
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1880
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1881
                   (unsigned long)zero_samples);
1882 1883 1884
#else
                fprintf(STDERR, " PASS\n");
#endif
1885
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1886 1887
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1888
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1889
                         k, (unsigned long)filters_used[k]);
1890
#endif
1891
#ifdef PNG_TIME_RFC1123_SUPPORTED
1892 1893
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1894 1895
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1896
         }
1897

1898 1899
         else
         {
1900
            if (verbose == 0 && i != 2)
1901
               fprintf(STDERR, "\n Testing %s:", inname);
1902

1903 1904
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1905
         }
1906
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1907 1908
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1909
               current_allocation - allocation_now);
1910

1911 1912
         if (current_allocation != 0)
         {
1913
             memory_infop pinfo = pinformation;
1914

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

1918 1919
             while (pinfo != NULL)
             {
1920 1921
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1922 1923 1924 1925
                pinfo = pinfo->next;
             }
          }
#endif
1926
       }
1927
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1928
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1929
          current_allocation);
1930
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1931
          maximum_allocation);
1932 1933 1934 1935
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1936
#endif
1937 1938
   }

1939 1940 1941 1942
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1943
   fprintf(STDERR, " CPU time used = %.3f seconds",
1944
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1945
   fprintf(STDERR, " (decoding %.3f,\n",
1946
      t_decode/(float)CLOCKS_PER_SEC);
1947
   fprintf(STDERR, "        encoding %.3f ,",
1948
      t_encode/(float)CLOCKS_PER_SEC);
1949
   fprintf(STDERR, " other %.3f seconds)\n\n",
1950 1951 1952
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1953
   if (ierror == 0)
1954
      fprintf(STDERR, " libpng passes test\n");
1955

1956
   else
1957
      fprintf(STDERR, " libpng FAILS test\n");
1958

1959
   return (int)(ierror != 0);
1960
}
1961 1962 1963 1964 1965 1966
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
1967 1968
   /* And skip this test */
   return 77;
1969 1970
}
#endif
1971

1972
/* Generate a compiler error if there is an old png.h in the search path. */
1973
typedef png_libpng_version_1_6_8beta02 Your_png_h_is_not_version_1_6_8beta02;