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

34 35
#define _POSIX_SOURCE 1

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

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

44
#include "png.h"
45

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

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

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

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

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

90 91 92 93 94 95 96 97 98
#if PNG_DEBUG > 1
#  define pngtest_debug(m)        ((void)fprintf(stderr, m "\n"))
#  define pngtest_debug1(m,p1)    ((void)fprintf(stderr, m "\n", p1))
#  define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2))
#else
#  define pngtest_debug(m)        ((void)0)
#  define pngtest_debug1(m,p1)    ((void)0)
#  define pngtest_debug2(m,p1,p2) ((void)0)
#endif
99

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

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

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

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

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

123
static int verbose = 0;
124
static int strict = 0;
125 126 127 128
static int relaxed = 0;
static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */
129

130 131 132 133 134
/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
#ifndef png_jmpbuf
#  define png_jmpbuf(png_ptr) png_ptr->jmpbuf
#endif

135 136 137 138 139 140 141 142 143 144 145
/* Defines for unknown chunk handling if required. */
#ifndef PNG_HANDLE_CHUNK_ALWAYS
#  define PNG_HANDLE_CHUNK_ALWAYS       3
#endif
#ifndef PNG_HANDLE_CHUNK_IF_SAFE
#  define PNG_HANDLE_CHUNK_IF_SAFE      2
#endif

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

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

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

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

164
   status_dots--;
165

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

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

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

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


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

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

206
static png_uint_32 zero_samples;
207

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

215
   /* Contents of row_info:
216 217 218 219 220 221 222 223
    *  png_uint_32 width      width of row
    *  png_uint_32 rowbytes   number of bytes in row
    *  png_byte color_type    color type of pixels
    *  png_byte bit_depth     bit depth of samples
    *  png_byte channels      number of channels (1-4)
    *  png_byte pixel_depth   bits per pixel (depth*channels)
    */

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

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

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

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

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

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

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

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

269
          if (row_info->bit_depth == 8)
270 271
             if (*dp++ == 0)
                zero_samples++;
272

273
          if (row_info->bit_depth == 16)
274
          {
275 276
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
277 278 279 280
             dp+=2;
          }
       }
    }
281
    else /* Other color types */
282
    {
283
       png_uint_32 n, nstop;
284 285
       int channel;
       int color_channels = row_info->channels;
286 287
       if (row_info->color_type > 3)
          color_channels--;
288

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

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

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

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

326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
#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 */
   }
363
   if (err != 0)
364 365 366 367
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

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

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

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

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

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

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

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

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

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

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

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

442
   ++warning_count;
443

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

611

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

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

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

635 636 637 638 639 640 641 642 643 644 645 646
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;

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

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

656
   else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0)
657 658 659 660 661 662 663 664 665 666 667 668 669
      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 */
}
670

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

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

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

703
         if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
704 705 706 707 708 709 710
         {
            my_user_chunk_data->sTER_mode=chunk->data[0];
            return (1);
         }

         else
            return (0); /* duplicate sTER - give it to libpng */
711 712 713 714 715 716 717 718 719 720 721
      }

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

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

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

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

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

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

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

static void
write_vpAg_chunk(png_structp write_ptr)
{
747
   png_byte vpAg[5] = {118, 112,  65, 103, '\0'};
748 749 750

   png_byte vpag_chunk_data[9];

751
   if (verbose != 0)
752 753 754 755 756 757 758 759
      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;
760
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
}

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

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

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

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

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

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

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

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

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

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

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

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

942
   if (strict != 0)
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
   {
      /* 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'.
       */
   }

958
   else if (relaxed != 0)
959 960 961 962 963 964 965 966 967
   {
      /* 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
   }

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

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

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

1002
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1003
   {
1004
      int i;
1005

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

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

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

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

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

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

A
Andreas Dilger 已提交
1052
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
1053
          &color_type, &interlace_type, &compression_type, &filter_type) != 0)
A
Andreas Dilger 已提交
1054 1055 1056
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
            color_type, interlace_type, compression_type, filter_type);
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
#ifndef PNG_READ_INTERLACING_SUPPORTED
         /* num_pass will not be set below, set it here if the image is
          * interlaced: what happens is that write interlacing is *not* turned
          * on an the partial interlaced rows are written directly.
          */
         switch (interlace_type)
         {
            case PNG_INTERLACE_NONE:
               num_pass = 1;
               break;

            case PNG_INTERLACE_ADAM7:
               num_pass = 7;
                break;

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

1085
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
1086
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
A
Andreas Dilger 已提交
1087
      {
1088 1089
         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 已提交
1090
      }
G
Guy Schalnat 已提交
1091
   }
A
Andreas Dilger 已提交
1092
#endif
1093
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1094
   {
1095
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1096

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

1108
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1109
         &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1110 1111 1112 1113 1114 1115
      {
         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
1116
#ifdef PNG_gAMA_SUPPORTED
1117 1118 1119
   {
      double gamma;

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

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

1145
      if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
1146 1147
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1148
#endif
1149 1150 1151 1152
   {
      png_colorp palette;
      int num_palette;

1153
      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
1154 1155
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1156
#ifdef PNG_bKGD_SUPPORTED
1157 1158 1159
   {
      png_color_16p background;

1160
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1161 1162 1163 1164 1165
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1166
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1167
   {
A
Andreas Dilger 已提交
1168 1169
      png_uint_16p hist;

1170
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1171
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1172
   }
A
Andreas Dilger 已提交
1173
#endif
1174
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1175
   {
1176
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1177
      int unit_type;
G
Guy Schalnat 已提交
1178

1179
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1180
          &unit_type) != 0)
A
Andreas Dilger 已提交
1181 1182 1183 1184 1185
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1186
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1187 1188 1189 1190 1191 1192 1193
   {
      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,
1194
         &nparams, &units, &params) != 0)
A
Andreas Dilger 已提交
1195 1196 1197 1198 1199 1200
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1201
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1202 1203 1204 1205
   {
      png_uint_32 res_x, res_y;
      int unit_type;

1206 1207
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1208 1209 1210
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1211
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1212
   {
1213
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1214

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

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

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

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

1257 1258
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1259
         if (verbose != 0)
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
         {
            int i;

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

A
Andreas Dilger 已提交
1271 1272 1273 1274
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1275
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1276 1277 1278
   {
      png_timep mod_time;

1279
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1280 1281
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1282
#ifdef PNG_TIME_RFC1123_SUPPORTED
1283
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1284
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1285 1286

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

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

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

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

1345
#ifdef PNG_WRITE_SUPPORTED
1346
   pngtest_debug("Writing info struct");
1347

1348 1349 1350 1351
   /* 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);
1352

1353
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1354

1355
   png_write_info(write_ptr, write_info_ptr);
1356

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

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

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

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

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

1388 1389
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1390

1391 1392
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
            (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1393

1394
#endif /* !SINGLE_ROWBUF_ALLOC */
1395
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1396 1397

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

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

1419 1420 1421 1422 1423 1424 1425
#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
1426 1427
#endif

1428
   pngtest_debug("Reading and writing end_info data");
1429

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

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1438
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1439 1440 1441

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1442
         if (verbose != 0)
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
         {
            int i;

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

1454 1455 1456 1457
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1458
#ifdef PNG_tIME_SUPPORTED
1459 1460 1461
   {
      png_timep mod_time;

1462
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1463 1464
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1465
#ifdef PNG_TIME_RFC1123_SUPPORTED
1466
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1467
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1468 1469

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

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

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

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

1523
   png_write_end(write_ptr, write_end_info_ptr);
1524
#endif
1525

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

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

1553 1554
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1555

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

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

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

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

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

1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
            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;
            }
1633

1634 1635
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1636

1637 1638
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1639

1640 1641 1642
            else
              return (0);
         }
1643

1644
         if (num_in == 0)
1645
            break;
1646

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

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

1665 1666
            FCLOSE(fpin);
            FCLOSE(fpout);
1667

1668 1669 1670 1671 1672 1673 1674
            /* 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);
1675

1676 1677 1678
            else
              return (0);
         }
G
Guy Schalnat 已提交
1679 1680
      }
   }
1681
#endif /* PNG_WRITE_SUPPORTED */
G
Guy Schalnat 已提交
1682

1683 1684
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1685

1686
   return (0);
G
Guy Schalnat 已提交
1687
}
G
Guy Schalnat 已提交
1688

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

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

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

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

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

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

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

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

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

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

1779
      else
1780
      {
1781
         inname = argv[1];
1782 1783
         status_dots_requested = 0;
      }
1784 1785
   }

1786
   if (multiple == 0 && argc == 3 + verbose)
1787
     outname = argv[2 + verbose];
1788

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

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

1837 1838 1839
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1840

1841 1842
         else
         {
1843 1844
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1845
         }
1846
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1847 1848
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1849
               current_allocation - allocation_now);
1850

1851 1852
         if (current_allocation != 0)
         {
1853 1854 1855 1856
            memory_infop pinfo = pinformation;

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

1858 1859
            while (pinfo != NULL)
            {
1860
               fprintf(STDERR, " %lu bytes at %p\n",
1861
                 (unsigned long)pinfo->size,
1862
                 pinfo->pointer);
1863
               pinfo = pinfo->next;
1864
            }
1865
         }
1866 1867
#endif
      }
1868
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1869
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1870
            current_allocation);
1871
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1872
            maximum_allocation);
1873 1874 1875 1876
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1877
#endif
1878
   }
1879

1880 1881
   else
   {
1882
      int i;
1883
      for (i = 0; i<3; ++i)
1884
      {
1885
         int kerror;
1886
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1887 1888
         int allocation_now = current_allocation;
#endif
1889 1890 1891 1892 1893 1894
         if (i == 1)
            status_dots_requested = 1;

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

1895
         if (i == 0 || verbose == 1 || ierror != 0)
1896
         {
1897
            fprintf(STDERR, "\n Testing %s:", inname);
1898 1899 1900 1901
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
1902

1903
         kerror = test_one_file(inname, outname);
1904

1905
         if (kerror == 0)
1906
         {
1907
            if (verbose == 1 || i == 2)
1908
            {
1909
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1910
                int k;
1911
#endif
1912
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1913
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1914
                   (unsigned long)zero_samples);
1915 1916 1917
#else
                fprintf(STDERR, " PASS\n");
#endif
1918
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1919
                for (k = 0; k<256; k++)
1920
                   if (filters_used[k] != 0)
1921
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1922
                         k, (unsigned long)filters_used[k]);
1923
#endif
1924
#ifdef PNG_TIME_RFC1123_SUPPORTED
1925 1926
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1927 1928
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1929
         }
1930

1931 1932
         else
         {
1933
            if (verbose == 0 && i != 2)
1934
            {
1935
               fprintf(STDERR, "\n Testing %s:", inname);
1936 1937 1938 1939
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
1940

1941 1942
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1943
         }
1944
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1945 1946
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1947
               current_allocation - allocation_now);
1948

1949 1950
         if (current_allocation != 0)
         {
1951
             memory_infop pinfo = pinformation;
1952

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

1956 1957
             while (pinfo != NULL)
             {
1958 1959
                fprintf(STDERR, " %lu bytes at %p\n",
                   (unsigned long)pinfo->size, pinfo->pointer);
1960 1961 1962 1963
                pinfo = pinfo->next;
             }
          }
#endif
1964
       }
1965
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1966
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1967
          current_allocation);
1968
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1969
          maximum_allocation);
1970 1971 1972 1973
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1974
#endif
1975 1976
   }

1977 1978 1979 1980
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1981
   fprintf(STDERR, " CPU time used = %.3f seconds",
1982
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1983
   fprintf(STDERR, " (decoding %.3f,\n",
1984
      t_decode/(float)CLOCKS_PER_SEC);
1985
   fprintf(STDERR, "        encoding %.3f ,",
1986
      t_encode/(float)CLOCKS_PER_SEC);
1987
   fprintf(STDERR, " other %.3f seconds)\n\n",
1988 1989 1990
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1991
   if (ierror == 0)
1992
      fprintf(STDERR, " libpng passes test\n");
1993

1994
   else
1995
      fprintf(STDERR, " libpng FAILS test\n");
1996

1997
   return (int)(ierror != 0);
1998
}
1999 2000 2001 2002 2003 2004
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
2005
   /* And skip this test */
2006
   return PNG_LIBPNG_VER < 10600 ? 0 : 77;
2007 2008
}
#endif
2009

2010
/* Generate a compiler error if there is an old png.h in the search path. */
2011
typedef png_libpng_version_1_6_15beta07 Your_png_h_is_not_version_1_6_15beta07;