pngtest.c 59.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.5.25 [December 3, 2015]
5
 * Copyright (c) 1998-2002,2004,2006-2015 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
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
 * a skipped test, in earlier versions we need to succeed on a skipped test, so:
 */
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#  define SKIP 77
#else
#  define SKIP 0
#endif

55 56
/* 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
57 58 59 60 61
 *
 * 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).
62 63 64 65 66 67 68 69 70 71 72
 */
#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 &&\
J
John Bowler 已提交
73
   defined PNG_READ_sPLT_SUPPORTED &&\
74 75
   defined PNG_READ_tEXt_SUPPORTED &&\
   defined PNG_READ_tIME_SUPPORTED &&\
76
   defined PNG_READ_zTXt_SUPPORTED &&\
J
John Bowler 已提交
77
   (defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700)
78 79 80 81 82 83

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

85 86 87 88
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
89
#define FCLOSE(file) fclose(file)
90

91
#ifndef PNG_STDIO_SUPPORTED
92
typedef FILE                * png_FILE_p;
93 94
#endif

95
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
96
#ifndef PNG_DEBUG
97 98 99
#  define PNG_DEBUG 0
#endif

100 101 102 103 104 105 106 107 108
#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
109

110
#if !PNG_DEBUG
111
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
112
#endif
A
Andreas Dilger 已提交
113

J
John Bowler 已提交
114 115 116 117
#ifndef PNG_UNUSED
#  define PNG_UNUSED(param) (void)param;
#endif

118 119 120 121
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

122
#ifndef PNG_FLOATING_POINT_SUPPORTED
123 124 125
#undef PNGTEST_TIMING
#endif

126 127 128 129 130
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

131
#ifdef PNG_TIME_RFC1123_SUPPORTED
132
#define PNG_tIME_STRING_LENGTH 29
133
static int tIME_chunk_present = 0;
134
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
J
John Bowler 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150

#if PNG_LIBPNG_VER < 10619
#define png_convert_to_rfc1123_buffer(ts, t) tIME_to_str(read_ptr, ts, t)

static int
tIME_to_str(png_structp png_ptr, png_charp ts, png_const_timep t)
{
    png_const_charp str = png_convert_to_rfc1123(png_ptr, t);

    if (str == NULL)
        return 0;

    strcpy(ts, str);
    return 1;
}
#endif /* older libpng */
151 152
#endif

153
static int verbose = 0;
154
static int strict = 0;
155 156 157 158
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 */
159

160 161 162 163 164
/* 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

165 166 167 168 169 170 171 172 173 174 175
/* 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))

176
/* Example of using row callbacks to make a simple progress meter */
177 178 179
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
180

181
static void PNGCBAPI
182
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
183
{
184 185
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
186

187 188 189 190 191 192
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
193

194
   status_dots--;
195

196 197 198 199 200
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
201

202
   fprintf(stdout, "r");
203
}
204

205 206
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
207
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
208
{
209 210
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
211

212
   fprintf(stdout, "w");
213
}
214
#endif
215 216


217
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
J
John Bowler 已提交
218
/* Example of using a user transform callback (doesn't do anything at present).
219
 */
220
static void PNGCBAPI
J
John Bowler 已提交
221
read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data)
222
{
J
John Bowler 已提交
223 224 225
   PNG_UNUSED(png_ptr)
   PNG_UNUSED(row_info)
   PNG_UNUSED(data)
226 227 228
}
#endif

229
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
230
/* Example of using user transform callback (we don't transform anything,
231 232
 * but merely count the zero samples)
 */
233

234
static png_uint_32 zero_samples;
235

236
static void PNGCBAPI
237
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
238 239
{
   png_bytep dp = data;
240 241
   if (png_ptr == NULL)
      return;
242

243
   /* Contents of row_info:
244 245 246 247 248 249 250 251
    *  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)
    */

252
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
253

254
    if (row_info->color_type == 0 || row_info->color_type == 3)
255
    {
256
       int pos = 0;
257
       png_uint_32 n, nstop;
258

259
       for (n = 0, nstop=row_info->width; n<nstop; n++)
260
       {
261
          if (row_info->bit_depth == 1)
262
          {
263 264
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
265

266
             if (pos == 8)
267
             {
268
                pos = 0;
269 270
                dp++;
             }
271
          }
272

273
          if (row_info->bit_depth == 2)
274
          {
275 276
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
277

278
             if (pos == 8)
279
             {
280
                pos = 0;
281 282
                dp++;
             }
283
          }
284

285
          if (row_info->bit_depth == 4)
286
          {
287 288
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
289

290
             if (pos == 8)
291
             {
292
                pos = 0;
293 294
                dp++;
             }
295
          }
296

297
          if (row_info->bit_depth == 8)
298 299
             if (*dp++ == 0)
                zero_samples++;
300

301
          if (row_info->bit_depth == 16)
302
          {
303 304
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
305 306 307 308
             dp+=2;
          }
       }
    }
309
    else /* Other color types */
310
    {
311
       png_uint_32 n, nstop;
312 313
       int channel;
       int color_channels = row_info->channels;
314 315
       if (row_info->color_type > 3)
          color_channels--;
316

317
       for (n = 0, nstop=row_info->width; n<nstop; n++)
318 319 320
       {
          for (channel = 0; channel < color_channels; channel++)
          {
321
             if (row_info->bit_depth == 8)
322 323
                if (*dp++ == 0)
                   zero_samples++;
324

325
             if (row_info->bit_depth == 16)
326
             {
327 328
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
329

330 331 332
                dp+=2;
             }
          }
333
          if (row_info->color_type > 3)
334 335
          {
             dp++;
336 337
             if (row_info->bit_depth == 16)
                dp++;
338 339 340 341
          }
       }
    }
}
342
#endif /* WRITE_USER_TRANSFORM */
343

344
#ifndef PNG_STDIO_SUPPORTED
345
/* START of code to validate stdio-free compilation */
346 347 348 349 350 351 352
/* 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.
 */
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
#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 */
   }
391
   if (err != 0)
392 393 394 395
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

396
static void PNGCBAPI
397
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
398
{
399 400
   png_size_t check = 0;
   png_voidp io_ptr;
401 402 403 404

   /* 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.
    */
405 406 407
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
408
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
409
   }
410

411 412
   if (check != length)
   {
413
      png_error(png_ptr, "Read Error");
414
   }
415 416 417 418

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

421
#ifdef PNG_WRITE_FLUSH_SUPPORTED
422
static void PNGCBAPI
423
pngtest_flush(png_structp png_ptr)
424
{
425
   /* Do nothing; fflush() is said to be just a waste of energy. */
426
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
427 428
}
#endif
G
Guy Schalnat 已提交
429

430
/* This is the function that does the actual writing of data.  If you are
431 432 433 434
 * 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.
 */
435
static void PNGCBAPI
436
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
437
{
438
   png_size_t check;
439

440
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
441

442 443 444 445
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
446 447 448 449

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
450
}
451
#endif /* !STDIO */
452 453 454 455 456 457

/* 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.
 */
458 459 460 461 462
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

463
static void PNGCBAPI
464
pngtest_warning(png_structp png_ptr, png_const_charp message)
465 466
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
467 468
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
469

470
   ++warning_count;
471

472 473 474 475
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
476 477 478 479 480 481 482
}

/* 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().
 */
483
static void PNGCBAPI
484
pngtest_error(png_structp png_ptr, png_const_charp message)
485
{
486 487
   ++error_count;

488
   pngtest_warning(png_ptr, message);
489
   /* We can return because png_error calls the default handler, which is
490 491
    * actually OK in this case.
    */
492
}
493

494 495
/* END of code to validate stdio-free compilation */

496
/* START of code to validate memory allocation and deallocation */
497
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
498 499

/* Allocate memory.  For reasonable files, size should never exceed
500
 * 64K.  However, zlib may allocate more than 64K if you don't tell
501 502 503 504 505 506 507
 * 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.
 */
508 509
typedef struct memory_information
{
510
   png_alloc_size_t          size;
511
   png_voidp                 pointer;
512
   struct memory_information *next;
513
} memory_information;
514
typedef memory_information *memory_infop;
515 516 517 518

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
519 520
static int total_allocation = 0;
static int num_allocations = 0;
521

522 523 524
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));
525 526

png_voidp
527
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
528
{
529

530
   /* png_malloc has already tested for NULL; png_create_struct calls
531 532
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
533

534
   if (size == 0)
535
      return (NULL);
536 537 538 539

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
540
      /* Disable malloc_fn and free_fn */
541
      memory_infop pinfo;
542
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
543
      pinfo = (memory_infop)png_malloc(png_ptr,
544
         (sizeof *pinfo));
545 546
      pinfo->size = size;
      current_allocation += size;
547 548
      total_allocation += size;
      num_allocations ++;
549

550 551
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
552

553
      pinfo->pointer = png_malloc(png_ptr, size);
554
      /* Restore malloc_fn and free_fn */
555

556 557
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
558

559 560 561 562
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
563
         png_error(png_ptr,
564
           "out of memory in pngtest->png_debug_malloc");
565
      }
566

567 568 569
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
570
      memset(pinfo->pointer, 0xdd, pinfo->size);
571

572
      if (verbose != 0)
573
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
574
            pinfo->pointer);
575

576
      return (png_voidp)(pinfo->pointer);
577 578 579 580
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
581
void PNGCBAPI
582
png_debug_free(png_structp png_ptr, png_voidp ptr)
583 584
{
   if (png_ptr == NULL)
585
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
586

587 588
   if (ptr == 0)
   {
589 590 591 592 593 594 595
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
596
   if (pinformation != NULL)
597
   {
598
      memory_infop *ppinfo = &pinformation;
599

600 601
      for (;;)
      {
602
         memory_infop pinfo = *ppinfo;
603

604 605
         if (pinfo->pointer == ptr)
         {
606 607 608 609 610
            *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
611
               the memory that is to be freed. */
612
            memset(ptr, 0x55, pinfo->size);
613
            free(pinfo);
614
            pinfo = NULL;
615 616
            break;
         }
617

618 619
         if (pinfo->next == NULL)
         {
620
            fprintf(STDERR, "Pointer %p not found\n", ptr);
621 622
            break;
         }
623

624 625 626 627 628
         ppinfo = &pinfo->next;
      }
   }

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

632
   if (ptr != NULL)
633
      free(ptr);
634
   ptr = NULL;
635
}
636
#endif /* USER_MEM && DEBUG */
637 638
/* END of code to test memory allocation/deallocation */

639

640
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
641 642
/* Demonstration of user chunk support of the sTER and vpAg chunks */

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

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
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
662

663 664 665 666 667 668 669 670 671 672 673 674
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;

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

678
   /* Find where we are (the code below zeroes info_ptr to indicate that the
679 680 681 682 683
    * chunks before the first IDAT have been read.)
    */
   if (data->info_ptr == NULL) /* after IDAT */
      location = what | after_IDAT;

684
   else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0)
685 686 687 688 689 690 691 692 693 694 695 696 697
      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 */
}
698

699
static int PNGCBAPI
700
read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
701
{
702 703 704 705 706
   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");
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726

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

728 729
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
730

731
         if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
732 733 734 735 736 737 738
         {
            my_user_chunk_data->sTER_mode=chunk->data[0];
            return (1);
         }

         else
            return (0); /* duplicate sTER - give it to libpng */
739 740 741 742 743 744 745 746 747 748 749
      }

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

750
   if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
751
      return (0);  /* duplicate vpAg */
752

753 754 755
   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];
756 757

   return (1);
758 759 760 761 762 763
}

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

766
   if (verbose != 0)
767
      fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode);
768

769
   png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1);
770
}
771 772 773 774

static void
write_vpAg_chunk(png_structp write_ptr)
{
775
   png_byte vpAg[5] = {118, 112,  65, 103, '\0'};
776 777 778

   png_byte vpag_chunk_data[9];

779
   if (verbose != 0)
780 781 782 783 784 785 786 787
      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;
788
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
}

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);
   }
}
811 812
#endif /* WRITE */
#else /* !READ_USER_CHUNKS */
813
#  define write_chunks(pp,loc) ((void)0)
814 815 816
#endif
/* END of code to demonstrate user chunk support */

817 818 819 820 821 822
/* 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
J
John Bowler 已提交
823
pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr,
824 825 826 827 828 829 830 831 832 833 834 835
   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;
J
John Bowler 已提交
836 837
               /* In libpng 1.7 this now does an app-error, so stop it: */
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
838 839 840 841 842 843 844
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
J
John Bowler 已提交
845
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
846 847 848 849 850 851 852 853 854 855 856 857 858
#           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 */

859
/* Test one file */
860
static int
861
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
862
{
863 864
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
865
   pngtest_error_parameters error_parameters;
866 867 868 869 870 871
   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;
J
John Bowler 已提交
872
#ifdef PNG_WRITE_FILTER_SUPPORTED
873
   int interlace_preserved = 1;
J
John Bowler 已提交
874 875
#endif /* WRITE_FILTER */
#else /* !WRITE */
876 877 878
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
J
John Bowler 已提交
879
#endif /* !WRITE */
G
Guy Schalnat 已提交
880
   png_bytep row_buf;
G
Guy Schalnat 已提交
881
   png_uint_32 y;
A
Andreas Dilger 已提交
882
   png_uint_32 width, height;
J
John Bowler 已提交
883 884
   volatile int num_passes;
   int pass;
A
Andreas Dilger 已提交
885
   int bit_depth, color_type;
886

887
   row_buf = NULL;
888
   error_parameters.file_name = inname;
G
Guy Schalnat 已提交
889

A
Andreas Dilger 已提交
890
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
891 892
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
893
      return (1);
G
Guy Schalnat 已提交
894 895
   }

A
Andreas Dilger 已提交
896
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
897
   {
G
Guy Schalnat 已提交
898
      fprintf(STDERR, "Could not open output file %s\n", outname);
899
      FCLOSE(fpin);
900
      return (1);
G
Guy Schalnat 已提交
901 902
   }

903
   pngtest_debug("Allocating read and write structures");
904
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
905
   read_ptr =
906
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
907
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
908
#else
909
   read_ptr =
910
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
911
#endif
912 913
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
914

915
#ifdef PNG_WRITE_SUPPORTED
916
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
917
   write_ptr =
918
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
919
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
920
#else
921
   write_ptr =
922
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
923
#endif
924 925
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
      pngtest_warning);
926
#endif
927
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
928
   read_info_ptr = png_create_info_struct(read_ptr);
929
   end_info_ptr = png_create_info_struct(read_ptr);
930 931
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
932
   write_end_info_ptr = png_create_info_struct(write_ptr);
933
#endif
G
Guy Schalnat 已提交
934

935 936 937 938 939 940
#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

941
#ifdef PNG_SETJMP_SUPPORTED
942
   pngtest_debug("Setting jmpbuf for read struct");
943
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
944
   {
945
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
946 947
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
948
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
949
#ifdef PNG_WRITE_SUPPORTED
950
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
951
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
952
#endif
953 954
      FCLOSE(fpin);
      FCLOSE(fpout);
955
      return (1);
G
Guy Schalnat 已提交
956
   }
A
Andreas Dilger 已提交
957

958
#ifdef PNG_WRITE_SUPPORTED
959
   pngtest_debug("Setting jmpbuf for write struct");
960

961
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
962
   {
963
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
964
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
965
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
966
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
967
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
968
#endif
969 970
      FCLOSE(fpin);
      FCLOSE(fpout);
971
      return (1);
G
Guy Schalnat 已提交
972
   }
973
#endif
A
Andreas Dilger 已提交
974
#endif
975

976
   if (strict != 0)
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
   {
      /* 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'.
       */
   }

992
   else if (relaxed != 0)
993 994 995 996 997 998 999 1000 1001
   {
      /* 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
   }

1002
   pngtest_debug("Initializing input and output streams");
1003
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
1004
   png_init_io(read_ptr, fpin);
1005
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
1006
   png_init_io(write_ptr, fpout);
1007
#  endif
1008
#else
1009
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
1010
#  ifdef PNG_WRITE_SUPPORTED
1011
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
1012
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
1013
      pngtest_flush);
1014
#    else
1015
      NULL);
1016 1017
#    endif
#  endif
1018
#endif
1019

1020
   if (status_dots_requested == 1)
1021
   {
1022
#ifdef PNG_WRITE_SUPPORTED
1023
      png_set_write_status_fn(write_ptr, write_row_callback);
1024
#endif
1025 1026
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
1027

1028 1029
   else
   {
1030
#ifdef PNG_WRITE_SUPPORTED
1031
      png_set_write_status_fn(write_ptr, NULL);
1032
#endif
1033
      png_set_read_status_fn(read_ptr, NULL);
1034 1035
   }

1036
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
J
John Bowler 已提交
1037
   png_set_read_user_transform_fn(read_ptr, read_user_callback);
1038
#endif
1039
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1040
   zero_samples = 0;
1041 1042
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
1043

1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
#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
1054 1055
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
1056
#endif
1057
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1058
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1059
      NULL, 0);
1060
#endif
1061 1062
#endif

1063
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
1064
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
1065

1066 1067 1068 1069 1070 1071 1072 1073 1074
#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

1075
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
1076 1077
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
1078

A
Andreas Dilger 已提交
1079
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
1080
          &color_type, &interlace_type, &compression_type, &filter_type) != 0)
A
Andreas Dilger 已提交
1081 1082 1083
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
            color_type, interlace_type, compression_type, filter_type);
J
John Bowler 已提交
1084 1085
         /* num_passes may not be available below if interlace support is not
          * provided by libpng for both read and write.
1086 1087 1088 1089
          */
         switch (interlace_type)
         {
            case PNG_INTERLACE_NONE:
J
John Bowler 已提交
1090
               num_passes = 1;
1091 1092 1093
               break;

            case PNG_INTERLACE_ADAM7:
J
John Bowler 已提交
1094 1095
               num_passes = 7;
               break;
1096 1097

            default:
J
John Bowler 已提交
1098 1099
               png_error(read_ptr, "invalid interlace type");
               /*NOT REACHED*/
1100
         }
A
Andreas Dilger 已提交
1101
      }
1102

J
John Bowler 已提交
1103 1104 1105
      else
         png_error(read_ptr, "png_get_IHDR failed");
   }
1106 1107
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1108
   {
1109
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1110
         blue_y;
1111

1112
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
1113
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
A
Andreas Dilger 已提交
1114
      {
1115 1116
         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 已提交
1117
      }
G
Guy Schalnat 已提交
1118
   }
A
Andreas Dilger 已提交
1119
#endif
1120
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1121
   {
1122
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1123

1124
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0)
1125
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1126 1127
   }
#endif
1128
#else /* Use floating point versions */
1129 1130
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1131 1132 1133
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1134

1135
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1136
         &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1137 1138 1139 1140 1141 1142
      {
         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
1143
#ifdef PNG_gAMA_SUPPORTED
1144 1145 1146
   {
      double gamma;

1147
      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0)
1148 1149 1150
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1151 1152
#endif /* Floating point */
#endif /* Fixed point */
1153
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1154
   {
1155
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1156
      png_bytep profile;
1157
      png_uint_32 proflen;
1158
      int compression_type;
A
Andreas Dilger 已提交
1159

1160
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
1161
                      &profile, &proflen) != 0)
A
Andreas Dilger 已提交
1162
      {
1163 1164
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1165
      }
G
Guy Schalnat 已提交
1166
   }
1167
#endif
1168
#ifdef PNG_sRGB_SUPPORTED
1169
   {
1170
      int intent;
1171

1172
      if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
1173 1174
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1175
#endif
1176 1177 1178 1179
   {
      png_colorp palette;
      int num_palette;

1180
      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
1181 1182
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1183
#ifdef PNG_bKGD_SUPPORTED
1184 1185 1186
   {
      png_color_16p background;

1187
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1188 1189 1190 1191 1192
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1193
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1194
   {
A
Andreas Dilger 已提交
1195 1196
      png_uint_16p hist;

1197
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1198
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1199
   }
A
Andreas Dilger 已提交
1200
#endif
1201
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1202
   {
1203
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1204
      int unit_type;
G
Guy Schalnat 已提交
1205

1206
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1207
          &unit_type) != 0)
A
Andreas Dilger 已提交
1208 1209 1210 1211 1212
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1213
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1214 1215 1216 1217 1218 1219 1220
   {
      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,
1221
         &nparams, &units, &params) != 0)
A
Andreas Dilger 已提交
1222 1223 1224 1225 1226 1227
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1228
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1229 1230 1231 1232
   {
      png_uint_32 res_x, res_y;
      int unit_type;

1233 1234
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1235 1236 1237
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1238
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1239
   {
1240
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1241

1242
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1243
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1244
   }
1245
#endif
1246
#ifdef PNG_sCAL_SUPPORTED
1247 1248
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1249
   {
1250
      int unit;
1251
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1252

1253
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1254
         &scal_height) != 0)
G
Guy Schalnat 已提交
1255
      {
1256
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1257 1258 1259
      }
   }
#else
1260
#ifdef PNG_FIXED_POINT_SUPPORTED
1261
   {
1262
      int unit;
1263
      png_charp scal_width, scal_height;
1264

1265
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1266
          &scal_height) != 0)
1267
      {
1268 1269
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1270 1271
      }
   }
J
John Bowler 已提交
1272 1273 1274
#endif
#endif
#endif
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285

#ifdef PNG_sPLT_SUPPORTED
   {
       png_sPLT_tp entries;

       int num_entries = (int) png_get_sPLT(read_ptr, read_info_ptr, &entries);
       if (num_entries)
       {
           png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries);
       }
   }
J
John Bowler 已提交
1286
#endif
1287

1288
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1289 1290 1291 1292 1293 1294
   {
      png_textp text_ptr;
      int num_text;

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

1297 1298
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1299
         if (verbose != 0)
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
         {
            int i;

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

A
Andreas Dilger 已提交
1311 1312 1313
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
J
John Bowler 已提交
1314
#endif
1315
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1316 1317 1318
   {
      png_timep mod_time;

1319
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1320 1321
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1322
#ifdef PNG_TIME_RFC1123_SUPPORTED
1323
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1324
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1325 1326

         else
1327 1328 1329 1330
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1331

1332
         tIME_chunk_present++;
1333
#endif /* TIME_RFC1123 */
1334
      }
A
Andreas Dilger 已提交
1335
   }
J
John Bowler 已提交
1336
#endif
1337
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1338
   {
1339
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1340
      int num_trans;
1341
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1342

1343
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1344
         &trans_color) != 0)
A
Andreas Dilger 已提交
1345
      {
1346
         int sample_max = (1 << bit_depth);
1347
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1348
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1349
             (int)trans_color->gray > sample_max) ||
1350
             (color_type == PNG_COLOR_TYPE_RGB &&
1351 1352 1353
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1354
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1355
               trans_color);
A
Andreas Dilger 已提交
1356 1357
      }
   }
J
John Bowler 已提交
1358
#endif
1359
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1360 1361
   {
      png_unknown_chunkp unknowns;
1362
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1363
         &unknowns);
1364

1365
      if (num_unknowns != 0)
1366 1367 1368
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1369
#if PNG_LIBPNG_VER < 10600
1370
         /* Copy the locations from the read_info_ptr.  The automatically
1371 1372
          * 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).
1373
          */
1374 1375 1376 1377 1378 1379 1380
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
1381 1382 1383
      }
   }
#endif
A
Andreas Dilger 已提交
1384

1385
#ifdef PNG_WRITE_SUPPORTED
1386
   pngtest_debug("Writing info struct");
1387

1388 1389 1390 1391
   /* 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);
1392

1393
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1394

1395
   png_write_info(write_ptr, write_info_ptr);
1396

1397
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1398
#endif
A
Andreas Dilger 已提交
1399

1400
#ifdef SINGLE_ROWBUF_ALLOC
1401
   pngtest_debug("Allocating row buffer...");
1402
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1403
      png_get_rowbytes(read_ptr, read_info_ptr));
1404

1405
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1406
#endif /* SINGLE_ROWBUF_ALLOC */
1407
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1408

J
John Bowler 已提交
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
#if defined(PNG_READ_INTERLACING_SUPPORTED) &&\
   defined(PNG_WRITE_INTERLACING_SUPPORTED)
   /* Both must be defined for libpng to be able to handle the interlace,
    * otherwise it gets handled below by simply reading and writing the passes
    * directly.
    */
   if (png_set_interlace_handling(read_ptr) != num_passes)
      png_error(write_ptr,
            "png_set_interlace_handling(read): wrong pass count ");
   if (png_set_interlace_handling(write_ptr) != num_passes)
      png_error(write_ptr,
            "png_set_interlace_handling(write): wrong pass count ");
#else /* png_set_interlace_handling not called on either read or write */
#  define calc_pass_height
#endif /* not using libpng interlace handling */
A
Andreas Dilger 已提交
1424

1425 1426 1427 1428 1429
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
J
John Bowler 已提交
1430
   for (pass = 0; pass < num_passes; pass++)
A
Andreas Dilger 已提交
1431
   {
J
John Bowler 已提交
1432 1433
#     ifdef calc_pass_height
         png_uint_32 pass_height;
1434

J
John Bowler 已提交
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
         if (num_passes == 7) /* interlaced */
         {
            if (PNG_PASS_COLS(width, pass) > 0)
               pass_height = PNG_PASS_ROWS(height, pass);

            else
               pass_height = 0;
         }

         else /* not interlaced */
            pass_height = height;
#     else
#        define pass_height height
#     endif

1450
      pngtest_debug1("Writing row data for pass %d", pass);
J
John Bowler 已提交
1451
      for (y = 0; y < pass_height; y++)
A
Andreas Dilger 已提交
1452
      {
1453
#ifndef SINGLE_ROWBUF_ALLOC
1454
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1455

1456 1457
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1458

1459 1460
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
            (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1461

1462
#endif /* !SINGLE_ROWBUF_ALLOC */
1463
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1464 1465

#ifdef PNG_WRITE_SUPPORTED
1466 1467 1468 1469 1470
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1471
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1472 1473 1474 1475 1476
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1477
#endif /* WRITE */
1478 1479

#ifndef SINGLE_ROWBUF_ALLOC
1480
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1481
         png_free(read_ptr, row_buf);
1482
         row_buf = NULL;
1483
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1484 1485 1486
      }
   }

1487 1488 1489 1490 1491 1492 1493
#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
1494 1495
#endif

1496
   pngtest_debug("Reading and writing end_info data");
1497

A
Andreas Dilger 已提交
1498
   png_read_end(read_ptr, end_info_ptr);
1499
#ifdef PNG_TEXT_SUPPORTED
1500 1501 1502 1503 1504 1505
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1506
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1507 1508 1509

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1510
         if (verbose != 0)
1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
         {
            int i;

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

1522 1523 1524 1525
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1526
#ifdef PNG_tIME_SUPPORTED
1527 1528 1529
   {
      png_timep mod_time;

1530
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1531 1532
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1533
#ifdef PNG_TIME_RFC1123_SUPPORTED
1534
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1535
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1536 1537

         else
1538 1539 1540 1541
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1542

1543
         tIME_chunk_present++;
1544
#endif /* TIME_RFC1123 */
1545 1546
      }
   }
1547
#endif
1548
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1549 1550
   {
      png_unknown_chunkp unknowns;
1551
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1552
         &unknowns);
1553

1554
      if (num_unknowns != 0)
1555 1556 1557
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1558
#if PNG_LIBPNG_VER < 10600
1559
         /* Copy the locations from the read_info_ptr.  The automatically
1560 1561
          * 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).
1562
          */
1563 1564 1565 1566 1567 1568 1569
         {
            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
1570 1571
      }
   }
1572
#endif
1573

1574
#ifdef PNG_WRITE_SUPPORTED
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
#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);

1591
   png_write_end(write_ptr, write_end_info_ptr);
1592
#endif
1593

1594
#ifdef PNG_EASY_ACCESS_SUPPORTED
1595
   if (verbose != 0)
1596 1597 1598 1599
   {
      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);
1600
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1601
         (unsigned long)iwidth, (unsigned long)iheight);
1602 1603
   }
#endif
G
Guy Schalnat 已提交
1604

1605
   pngtest_debug("Destroying data structs");
1606
#ifdef SINGLE_ROWBUF_ALLOC
1607
   pngtest_debug("destroying row_buf for read_ptr");
1608
   png_free(read_ptr, row_buf);
1609
   row_buf = NULL;
1610
#endif /* SINGLE_ROWBUF_ALLOC */
1611
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1612
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1613
#ifdef PNG_WRITE_SUPPORTED
1614
   pngtest_debug("destroying write_end_info_ptr");
1615
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1616
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1617
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1618
#endif
1619
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1620

1621 1622
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1623

1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
   /* 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
J
John Bowler 已提交
1641
      /* If there is no write support nothing was written! */
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657
      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);
   }

1658
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1659
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1660
   {
G
Guy Schalnat 已提交
1661
      fprintf(STDERR, "Could not find file %s\n", inname);
1662
      return (1);
G
Guy Schalnat 已提交
1663 1664
   }

A
Andreas Dilger 已提交
1665
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1666
   {
G
Guy Schalnat 已提交
1667
      fprintf(STDERR, "Could not find file %s\n", outname);
1668
      FCLOSE(fpin);
1669
      return (1);
G
Guy Schalnat 已提交
1670
   }
A
Andreas Dilger 已提交
1671

J
John Bowler 已提交
1672 1673
#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
    defined (PNG_WRITE_FILTER_SUPPORTED)
1674
   if (interlace_preserved != 0) /* else the files will be changed */
G
Guy Schalnat 已提交
1675
   {
1676
      for (;;)
1677
      {
1678
         static int wrote_question = 0;
1679 1680 1681
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];

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

1685
         if (num_in != num_out)
1686
         {
1687 1688
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);
1689

1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
            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;
            }
1702

1703 1704
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1705

1706 1707
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1708

1709 1710 1711
            else
              return (0);
         }
1712

1713
         if (num_in == 0)
1714
            break;
1715

1716
         if (memcmp(inbuf, outbuf, num_in))
1717
         {
1718 1719 1720 1721 1722 1723
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1724
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1725 1726 1727 1728 1729 1730 1731 1732
                    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;
            }
1733

1734 1735
            FCLOSE(fpin);
            FCLOSE(fpout);
1736

1737 1738 1739 1740 1741 1742 1743
            /* 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);
1744

1745 1746 1747
            else
              return (0);
         }
G
Guy Schalnat 已提交
1748 1749
      }
   }
J
John Bowler 已提交
1750
#endif /* WRITE && WRITE_FILTER */
G
Guy Schalnat 已提交
1751

1752 1753
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1754

1755
   return (0);
G
Guy Schalnat 已提交
1756
}
G
Guy Schalnat 已提交
1757

1758
/* Input and output filenames */
1759
#ifdef RISCOS
1760 1761
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1762
#else
1763 1764
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1765 1766 1767 1768 1769 1770 1771 1772
#endif

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

1773 1774
   png_structp dummy_ptr;

1775
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1776
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1777
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1778
   /* Show the version of libpng used in building the library */
1779 1780
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1781
      png_get_header_version(NULL));
1782

1783
   /* Show the version of libpng used in building the application */
1784
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1785
      PNG_HEADER_VERSION_STRING);
1786 1787

   /* Do some consistency checking on the memory allocation settings, I'm
1788 1789 1790 1791
    * 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
    */
1792
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1793
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1794
#endif
1795
   /* I think the following can happen. */
1796
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1797
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1798
#endif
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810

   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)
   {
1811
      if (strcmp(argv[1], "-m") == 0)
1812
      {
1813
         multiple = 1;
1814 1815
         status_dots_requested = 0;
      }
1816

1817 1818 1819 1820 1821
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1822
         status_dots_requested = 1;
1823
      }
1824

1825 1826 1827
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1828
         status_dots_requested = 1;
1829 1830
         inname = argv[2];
      }
1831

1832 1833 1834 1835 1836 1837
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
         relaxed = 0;
      }

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

1850
      else
1851
      {
1852
         inname = argv[1];
1853 1854
         status_dots_requested = 0;
      }
1855 1856
   }

1857
   if (multiple == 0 && argc == 3 + verbose)
1858
     outname = argv[2 + verbose];
1859

1860 1861
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
1862
   {
1863 1864
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1865
        argv[0], argv[0]);
1866 1867 1868 1869
     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);
1870 1871 1872
     exit(1);
   }

1873
   if (multiple != 0)
1874 1875
   {
      int i;
1876
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1877 1878
      int allocation_now = current_allocation;
#endif
1879
      for (i=2; i<argc; ++i)
1880
      {
1881
         int kerror;
1882
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1883 1884 1885
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
1886
         kerror = test_one_file(argv[i], outname);
1887
         if (kerror == 0)
1888
         {
1889
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1890
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1891
               (unsigned long)zero_samples);
1892
#else
1893
            fprintf(STDERR, " PASS\n");
1894
#endif
1895
#ifdef PNG_TIME_RFC1123_SUPPORTED
1896 1897
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
1898

1899
            tIME_chunk_present = 0;
1900
#endif /* TIME_RFC1123 */
1901
         }
1902

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

1913 1914
         if (current_allocation != 0)
         {
1915 1916 1917 1918
            memory_infop pinfo = pinformation;

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

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

1942 1943
   else
   {
1944
      int i;
1945
      for (i = 0; i<3; ++i)
1946
      {
1947
         int kerror;
1948
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1949 1950
         int allocation_now = current_allocation;
#endif
1951 1952 1953 1954 1955 1956
         if (i == 1)
            status_dots_requested = 1;

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

1957
         if (i == 0 || verbose == 1 || ierror != 0)
1958
         {
1959
            fprintf(STDERR, "\n Testing %s:", inname);
1960 1961 1962 1963
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
1964

1965
         kerror = test_one_file(inname, outname);
1966

1967
         if (kerror == 0)
1968
         {
1969
            if (verbose == 1 || i == 2)
1970
            {
1971
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1972
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1973
                   (unsigned long)zero_samples);
1974 1975 1976
#else
                fprintf(STDERR, " PASS\n");
#endif
1977
#ifdef PNG_TIME_RFC1123_SUPPORTED
1978 1979
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1980
#endif /* TIME_RFC1123 */
1981
            }
1982
         }
1983

1984 1985
         else
         {
1986
            if (verbose == 0 && i != 2)
1987
            {
1988
               fprintf(STDERR, "\n Testing %s:", inname);
1989 1990 1991 1992
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
1993

1994 1995
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1996
         }
1997
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1998 1999
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
2000
               current_allocation - allocation_now);
2001

2002 2003
         if (current_allocation != 0)
         {
2004
             memory_infop pinfo = pinformation;
2005

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

2009 2010
             while (pinfo != NULL)
             {
2011 2012
                fprintf(STDERR, " %lu bytes at %p\n",
                   (unsigned long)pinfo->size, pinfo->pointer);
2013 2014 2015 2016
                pinfo = pinfo->next;
             }
          }
#endif
2017
       }
2018
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2019
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
2020
          current_allocation);
2021
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
2022
          maximum_allocation);
2023 2024 2025 2026
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
2027
#endif
2028 2029
   }

2030 2031 2032 2033
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
2034
   fprintf(STDERR, " CPU time used = %.3f seconds",
2035
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
2036
   fprintf(STDERR, " (decoding %.3f,\n",
2037
      t_decode/(float)CLOCKS_PER_SEC);
2038
   fprintf(STDERR, "        encoding %.3f ,",
2039
      t_encode/(float)CLOCKS_PER_SEC);
2040
   fprintf(STDERR, " other %.3f seconds)\n\n",
2041 2042 2043
      t_misc/(float)CLOCKS_PER_SEC);
#endif

2044
   if (ierror == 0)
2045
      fprintf(STDERR, " libpng passes test\n");
2046

2047
   else
2048
      fprintf(STDERR, " libpng FAILS test\n");
2049

2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
   dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   fprintf(STDERR, " Default limits:\n");
   fprintf(STDERR, "  width_max  = %lu\n",
      (unsigned long) png_get_user_width_max(dummy_ptr));
   fprintf(STDERR, "  height_max = %lu\n",
      (unsigned long) png_get_user_height_max(dummy_ptr));
   if (png_get_chunk_cache_max(dummy_ptr) == 0)
      fprintf(STDERR, "  cache_max  = unlimited\n");
   else
      fprintf(STDERR, "  cache_max  = %lu\n",
         (unsigned long) png_get_chunk_cache_max(dummy_ptr));
   if (png_get_chunk_malloc_max(dummy_ptr) == 0)
      fprintf(STDERR, "  malloc_max = unlimited\n");
   else
      fprintf(STDERR, "  malloc_max = %lu\n",
         (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
   png_destroy_read_struct(&dummy_ptr, NULL, NULL);

2068
   return (int)(ierror != 0);
2069
}
2070 2071 2072 2073 2074 2075
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
2076
   /* And skip this test */
2077
   return SKIP;
2078 2079
}
#endif
2080

2081
/* Generate a compiler error if there is an old png.h in the search path. */
2082
typedef png_libpng_version_1_6_24beta05 Your_png_h_is_not_version_1_6_24beta05;