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

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

34 35
#define _POSIX_SOURCE 1

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

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

44
#include "png.h"
45

46 47 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

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

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

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

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

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

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

157
   status_dots--;
158

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

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

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

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


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

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

199
static png_uint_32 zero_samples;
200

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

308
#ifndef PNG_STDIO_SUPPORTED
309
/* START of code to validate stdio-free compilation */
310 311 312 313 314 315 316
/* 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.
 */
317

318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
#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

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

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

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

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

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

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

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

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

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

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

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

434
   ++warning_count;
435

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

601

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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)
776 777 778
#endif
/* END of code to demonstrate user chunk support */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

991
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
992
   {
993
      int i;
994

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1228 1229
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

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

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

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

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

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

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

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

1316
#ifdef PNG_WRITE_SUPPORTED
1317
   pngtest_debug("Writing info struct");
1318

1319 1320 1321 1322
   /* 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);
1323

1324
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1325

1326
   png_write_info(write_ptr, write_info_ptr);
1327

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

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

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

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

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

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

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

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

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

1393
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1394
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1395
#endif
1396
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1397
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1398 1399
#endif

1400
   pngtest_debug("Reading and writing end_info data");
1401

A
Andreas Dilger 已提交
1402
   png_read_end(read_ptr, end_info_ptr);
1403
#ifdef PNG_TEXT_SUPPORTED
1404 1405 1406 1407 1408 1409
   {
      png_textp text_ptr;
      int num_text;

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

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

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

         else
1442 1443 1444 1445
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1446

1447 1448 1449 1450
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1451
#endif
1452
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1453 1454
   {
      png_unknown_chunkp unknowns;
1455
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1456
         &unknowns);
1457

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

1478
#ifdef PNG_WRITE_SUPPORTED
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494
#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);

1495
   png_write_end(write_ptr, write_end_info_ptr);
1496
#endif
1497

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

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

1525 1526
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1527

1528 1529 1530 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
   /* 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);
   }

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

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

1576
#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
G
Guy Schalnat 已提交
1577
   {
1578
      int wrote_question = 0;
1579

1580
      for (;;)
1581
      {
1582 1583 1584 1585 1586 1587
         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);
1588

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

1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605
            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;
            }
1606

1607 1608
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1609

1610 1611
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1612

1613 1614 1615
            else
              return (0);
         }
1616

1617 1618
         if (!num_in)
            break;
1619

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

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

1638 1639
            FCLOSE(fpin);
            FCLOSE(fpout);
1640

1641 1642 1643 1644 1645 1646 1647
            /* 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);
1648

1649 1650 1651
            else
              return (0);
         }
G
Guy Schalnat 已提交
1652 1653
      }
   }
1654
#endif /* PNG_WRITE_SUPPORTED */
G
Guy Schalnat 已提交
1655

1656 1657
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1658

1659
   return (0);
G
Guy Schalnat 已提交
1660
}
G
Guy Schalnat 已提交
1661

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

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

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

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

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

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

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

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

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

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

1752
      else
1753
      {
1754
         inname = argv[1];
1755 1756
         status_dots_requested = 0;
      }
1757 1758
   }

1759 1760
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1761

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

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

1806 1807 1808
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1809

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

1820 1821
         if (current_allocation != 0)
         {
1822 1823 1824 1825
            memory_infop pinfo = pinformation;

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

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

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

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

1864
         if (i == 0 || verbose == 1 || ierror != 0)
1865
            fprintf(STDERR, "\n Testing %s:", inname);
1866

1867
         kerror = test_one_file(inname, outname);
1868

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

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

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

1908 1909
         if (current_allocation != 0)
         {
1910
             memory_infop pinfo = pinformation;
1911

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

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

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

1950
   if (ierror == 0)
1951
      fprintf(STDERR, " libpng passes test\n");
1952

1953
   else
1954
      fprintf(STDERR, " libpng FAILS test\n");
1955

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

1969
/* Generate a compiler error if there is an old png.h in the search path. */
1970
typedef png_libpng_version_1_6_2rc01 Your_png_h_is_not_version_1_6_2rc01;