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

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * Last changed in libpng 1.6.25 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2002,2004,2006-2016 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

#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)
{
142
   png_const_charp str = png_convert_to_rfc1123(png_ptr, t);
J
John Bowler 已提交
143

144 145
   if (str == NULL)
       return 0;
J
John Bowler 已提交
146

147 148
   strcpy(ts, str);
   return 1;
J
John Bowler 已提交
149 150
}
#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 255 256 257
   if (row_info->color_type == 0 || row_info->color_type == 3)
   {
      int pos = 0;
      png_uint_32 n, nstop;
258

259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
      for (n = 0, nstop=row_info->width; n<nstop; n++)
      {
         if (row_info->bit_depth == 1)
         {
            if (((*dp << pos++ ) & 0x80) == 0)
               zero_samples++;

            if (pos == 8)
            {
               pos = 0;
               dp++;
            }
         }

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

            if (pos == 8)
            {
               pos = 0;
               dp++;
            }
         }

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

            if (pos == 8)
            {
               pos = 0;
               dp++;
            }
         }

         if (row_info->bit_depth == 8)
            if (*dp++ == 0)
               zero_samples++;

         if (row_info->bit_depth == 16)
         {
            if ((*dp | *(dp+1)) == 0)
               zero_samples++;
            dp+=2;
         }
      }
   }
   else /* Other color types */
   {
      png_uint_32 n, nstop;
      int channel;
      int color_channels = row_info->channels;
      if (row_info->color_type > 3)
         color_channels--;

      for (n = 0, nstop=row_info->width; n<nstop; n++)
      {
         for (channel = 0; channel < color_channels; channel++)
         {
            if (row_info->bit_depth == 8)
               if (*dp++ == 0)
                  zero_samples++;

            if (row_info->bit_depth == 16)
            {
               if ((*dp | *(dp+1)) == 0)
                  zero_samples++;

               dp+=2;
            }
         }
         if (row_info->color_type > 3)
         {
            dp++;
            if (row_info->bit_depth == 16)
               dp++;
         }
      }
   }
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
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
357
    png_uint_32 io_op);
358 359
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
360
    png_uint_32 io_op)
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
{
   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

static memory_infop pinformation = NULL;
517 518 519 520
static png_alloc_size_t current_allocation = 0;
static png_alloc_size_t maximum_allocation = 0;
static png_alloc_size_t total_allocation = 0;
static png_alloc_size_t 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
            *ppinfo = pinfo->next;
607
            if (current_allocation < pinfo->size)
608
               fprintf(STDERR, "Duplicate free of memory\n");
609 610
            else
               current_allocation -= pinfo->size;
611
            /* We must free the list element too, but first kill
612
               the memory that is to be freed. */
613
            memset(ptr, 0x55, pinfo->size);
614
            free(pinfo);
615
            pinfo = NULL;
616 617
            break;
         }
618

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

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

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

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

640

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   png_byte vpag_chunk_data[9];

780
   if (verbose != 0)
781
      fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
782 783 784
          (unsigned long)user_chunk_data.vpAg_width,
          (unsigned long)user_chunk_data.vpAg_height,
          user_chunk_data.vpAg_units);
785 786 787 788

   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;
789
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
}

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

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

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

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

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

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

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

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

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

936 937 938
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   init_callback_info(read_info_ptr);
   png_set_read_user_chunk_fn(read_ptr, &user_chunk_data,
939
       read_user_chunk_callback);
940 941
#endif

942 943 944 945 946 947
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
#  ifdef CHUNK_LIMIT /* from the build, for testing */
      png_set_chunk_malloc_max(read_ptr, CHUNK_LIMIT);
#  endif /* CHUNK_LIMIT */
#endif

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

965
#ifdef PNG_WRITE_SUPPORTED
966
   pngtest_debug("Setting jmpbuf for write struct");
967

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

983
   if (strict != 0)
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
   {
      /* 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'.
       */
   }

999
   else if (relaxed != 0)
1000 1001 1002 1003 1004 1005 1006 1007 1008
   {
      /* 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
   }

1009
   pngtest_debug("Initializing input and output streams");
1010
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
1011
   png_init_io(read_ptr, fpin);
1012
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
1013
   png_init_io(write_ptr, fpout);
1014
#  endif
1015
#else
1016
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
1017
#  ifdef PNG_WRITE_SUPPORTED
1018
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
1019
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
1020
       pngtest_flush);
1021
#    else
1022
       NULL);
1023 1024
#    endif
#  endif
1025
#endif
1026

1027
   if (status_dots_requested == 1)
1028
   {
1029
#ifdef PNG_WRITE_SUPPORTED
1030
      png_set_write_status_fn(write_ptr, write_row_callback);
1031
#endif
1032 1033
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
1034

1035 1036
   else
   {
1037
#ifdef PNG_WRITE_SUPPORTED
1038
      png_set_write_status_fn(write_ptr, NULL);
1039
#endif
1040
      png_set_read_status_fn(read_ptr, NULL);
1041 1042
   }

1043
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
J
John Bowler 已提交
1044
   png_set_read_user_transform_fn(read_ptr, read_user_callback);
1045
#endif
1046
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1047
   zero_samples = 0;
1048 1049
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
1050

1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
#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
1061
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1062
       NULL, 0);
1063
#endif
1064
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1065
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1066
       NULL, 0);
1067
#endif
1068 1069
#endif

1070
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
1071
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
1072

1073 1074 1075 1076 1077 1078 1079 1080 1081
#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

1082
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
1083 1084
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
1085

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

            case PNG_INTERLACE_ADAM7:
J
John Bowler 已提交
1101 1102
               num_passes = 7;
               break;
1103 1104

            default:
J
John Bowler 已提交
1105 1106
               png_error(read_ptr, "invalid interlace type");
               /*NOT REACHED*/
1107
         }
A
Andreas Dilger 已提交
1108
      }
1109

J
John Bowler 已提交
1110 1111 1112
      else
         png_error(read_ptr, "png_get_IHDR failed");
   }
1113 1114
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1115
   {
1116
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1117
          blue_y;
1118

1119
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
1120
          &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
A
Andreas Dilger 已提交
1121
      {
1122
         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
1123
             red_y, green_x, green_y, blue_x, blue_y);
A
Andreas Dilger 已提交
1124
      }
G
Guy Schalnat 已提交
1125
   }
A
Andreas Dilger 已提交
1126
#endif
1127
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1128
   {
1129
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1130

1131
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0)
1132
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1133 1134
   }
#endif
1135
#else /* Use floating point versions */
1136 1137
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1138 1139
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1140
          blue_y;
1141

1142
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1143
          &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1144 1145
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
1146
             red_y, green_x, green_y, blue_x, blue_y);
1147 1148 1149
      }
   }
#endif
1150
#ifdef PNG_gAMA_SUPPORTED
1151 1152 1153
   {
      double gamma;

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

1167
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
1168
          &profile, &proflen) != 0)
A
Andreas Dilger 已提交
1169
      {
1170
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
1171
             profile, proflen);
A
Andreas Dilger 已提交
1172
      }
G
Guy Schalnat 已提交
1173
   }
1174
#endif
1175
#ifdef PNG_sRGB_SUPPORTED
1176
   {
1177
      int intent;
1178

1179
      if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
1180 1181
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1182
#endif
1183 1184 1185 1186
   {
      png_colorp palette;
      int num_palette;

1187
      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
1188 1189
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1190
#ifdef PNG_bKGD_SUPPORTED
1191 1192 1193
   {
      png_color_16p background;

1194
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1195 1196 1197 1198 1199
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1200
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1201
   {
A
Andreas Dilger 已提交
1202 1203
      png_uint_16p hist;

1204
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1205
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1206
   }
A
Andreas Dilger 已提交
1207
#endif
1208
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1209
   {
1210
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1211
      int unit_type;
G
Guy Schalnat 已提交
1212

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

1240 1241
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1242 1243 1244
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1245
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1246
   {
1247
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1248

1249
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1250
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1251
   }
1252
#endif
1253
#ifdef PNG_sCAL_SUPPORTED
1254 1255
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1256
   {
1257
      int unit;
1258
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1259

1260
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1261
          &scal_height) != 0)
G
Guy Schalnat 已提交
1262
      {
1263
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1264 1265 1266
      }
   }
#else
1267
#ifdef PNG_FIXED_POINT_SUPPORTED
1268
   {
1269
      int unit;
1270
      png_charp scal_width, scal_height;
1271

1272
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1273
           &scal_height) != 0)
1274
      {
1275 1276
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1277 1278
      }
   }
J
John Bowler 已提交
1279 1280 1281
#endif
#endif
#endif
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292

#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 已提交
1293
#endif
1294

1295
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1296 1297 1298 1299 1300 1301
   {
      png_textp text_ptr;
      int num_text;

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

1304 1305
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1306
         if (verbose != 0)
1307 1308 1309 1310 1311 1312 1313
         {
            int i;

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

A
Andreas Dilger 已提交
1318 1319 1320
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
J
John Bowler 已提交
1321
#endif
1322
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1323 1324 1325
   {
      png_timep mod_time;

1326
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1327 1328
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1329
#ifdef PNG_TIME_RFC1123_SUPPORTED
1330
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1331
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1332 1333

         else
1334 1335 1336 1337
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1338

1339
         tIME_chunk_present++;
1340
#endif /* TIME_RFC1123 */
1341
      }
A
Andreas Dilger 已提交
1342
   }
J
John Bowler 已提交
1343
#endif
1344
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1345
   {
1346
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1347
      int num_trans;
1348
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1349

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

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

1392
#ifdef PNG_WRITE_SUPPORTED
1393
   pngtest_debug("Writing info struct");
1394

1395 1396 1397 1398
   /* 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);
1399

1400
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1401

1402
   png_write_info(write_ptr, write_info_ptr);
1403

1404
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1405
#endif
A
Andreas Dilger 已提交
1406

1407
#ifdef SINGLE_ROWBUF_ALLOC
1408
   pngtest_debug("Allocating row buffer...");
1409
   row_buf = (png_bytep)png_malloc(read_ptr,
1410
       png_get_rowbytes(read_ptr, read_info_ptr));
1411

1412
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1413
#endif /* SINGLE_ROWBUF_ALLOC */
1414
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1415

J
John Bowler 已提交
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,
1424
          "png_set_interlace_handling(read): wrong pass count ");
J
John Bowler 已提交
1425 1426
   if (png_set_interlace_handling(write_ptr) != num_passes)
      png_error(write_ptr,
1427
          "png_set_interlace_handling(write): wrong pass count ");
J
John Bowler 已提交
1428 1429 1430
#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 已提交
1431

1432 1433 1434 1435 1436
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
J
John Bowler 已提交
1437
   for (pass = 0; pass < num_passes; pass++)
A
Andreas Dilger 已提交
1438
   {
J
John Bowler 已提交
1439 1440
#     ifdef calc_pass_height
         png_uint_32 pass_height;
1441

J
John Bowler 已提交
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
         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

1457
      pngtest_debug1("Writing row data for pass %d", pass);
J
John Bowler 已提交
1458
      for (y = 0; y < pass_height; y++)
A
Andreas Dilger 已提交
1459
      {
1460
#ifndef SINGLE_ROWBUF_ALLOC
1461
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1462

1463
         row_buf = (png_bytep)png_malloc(read_ptr,
1464
             png_get_rowbytes(read_ptr, read_info_ptr));
1465

1466
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
1467
             (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1468

1469
#endif /* !SINGLE_ROWBUF_ALLOC */
1470
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1471 1472

#ifdef PNG_WRITE_SUPPORTED
1473 1474 1475 1476 1477
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1478
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1479 1480 1481 1482 1483
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1484
#endif /* WRITE */
1485 1486

#ifndef SINGLE_ROWBUF_ALLOC
1487
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1488
         png_free(read_ptr, row_buf);
1489
         row_buf = NULL;
1490
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1491 1492 1493
      }
   }

1494 1495 1496 1497 1498 1499 1500
#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
1501 1502
#endif

1503
   pngtest_debug("Reading and writing end_info data");
1504

A
Andreas Dilger 已提交
1505
   png_read_end(read_ptr, end_info_ptr);
1506
#ifdef PNG_TEXT_SUPPORTED
1507 1508 1509 1510 1511 1512
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1513
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1514 1515 1516

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1517
         if (verbose != 0)
1518 1519 1520 1521 1522 1523 1524
         {
            int i;

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

1529 1530 1531 1532
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1533
#ifdef PNG_tIME_SUPPORTED
1534 1535 1536
   {
      png_timep mod_time;

1537
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1538 1539
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1540
#ifdef PNG_TIME_RFC1123_SUPPORTED
1541
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1542
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1543 1544

         else
1545 1546 1547 1548
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1549

1550
         tIME_chunk_present++;
1551
#endif /* TIME_RFC1123 */
1552 1553
      }
   }
1554
#endif
1555
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1556 1557
   {
      png_unknown_chunkp unknowns;
1558
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1559
          &unknowns);
1560

1561
      if (num_unknowns != 0)
1562 1563
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1564
             num_unknowns);
1565
#if PNG_LIBPNG_VER < 10600
1566
         /* Copy the locations from the read_info_ptr.  The automatically
1567 1568
          * 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).
1569
          */
1570 1571 1572 1573
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1574
                  unknowns[i].location);
1575 1576
         }
#endif
1577 1578
      }
   }
1579
#endif
1580

1581
#ifdef PNG_WRITE_SUPPORTED
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
#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);

1598
   png_write_end(write_ptr, write_end_info_ptr);
1599
#endif
1600

1601
#ifdef PNG_EASY_ACCESS_SUPPORTED
1602
   if (verbose != 0)
1603 1604 1605 1606
   {
      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);
1607
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1608
          (unsigned long)iwidth, (unsigned long)iheight);
1609 1610
   }
#endif
G
Guy Schalnat 已提交
1611

1612
   pngtest_debug("Destroying data structs");
1613
#ifdef SINGLE_ROWBUF_ALLOC
1614
   pngtest_debug("destroying row_buf for read_ptr");
1615
   png_free(read_ptr, row_buf);
1616
   row_buf = NULL;
1617
#endif /* SINGLE_ROWBUF_ALLOC */
1618
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1619
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1620
#ifdef PNG_WRITE_SUPPORTED
1621
   pngtest_debug("destroying write_end_info_ptr");
1622
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1623
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1624
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1625
#endif
1626
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1627

1628 1629
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
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)",
1641
          inname, error_count, warning_count);
1642 1643 1644 1645 1646 1647

      if (strict != 0)
         return (1);
   }

#  ifdef PNG_WRITE_SUPPORTED
J
John Bowler 已提交
1648
      /* If there is no write support nothing was written! */
1649 1650 1651
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
1652
             inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
1653 1654 1655 1656 1657 1658
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
1659
          inname, warning_count);
1660 1661 1662 1663 1664

      if (strict != 0)
         return (1);
   }

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

A
Andreas Dilger 已提交
1672
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1673
   {
G
Guy Schalnat 已提交
1674
      fprintf(STDERR, "Could not find file %s\n", outname);
1675
      FCLOSE(fpin);
1676
      return (1);
G
Guy Schalnat 已提交
1677
   }
A
Andreas Dilger 已提交
1678

J
John Bowler 已提交
1679 1680
#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
    defined (PNG_WRITE_FILTER_SUPPORTED)
1681
   if (interlace_preserved != 0) /* else the files will be changed */
G
Guy Schalnat 已提交
1682
   {
1683
      for (;;)
1684
      {
1685
         static int wrote_question = 0;
1686 1687 1688
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];

1689 1690
         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1691

1692
         if (num_in != num_out)
1693
         {
1694
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1695
                inname, outname);
1696

1697 1698 1699
            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1700 1701 1702
                   "   Was %s written with the same maximum IDAT"
                   " chunk size (%d bytes),",
                   inname, PNG_ZBUF_SIZE);
1703
               fprintf(STDERR,
1704
                   "\n   filtering heuristic (libpng default), compression");
1705
               fprintf(STDERR,
1706 1707
                   " level (zlib default),\n   and zlib version (%s)?\n\n",
                   ZLIB_VERSION);
1708 1709
               wrote_question = 1;
            }
1710

1711 1712
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1713

1714 1715
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1716

1717 1718 1719
            else
              return (0);
         }
1720

1721
         if (num_in == 0)
1722
            break;
1723

1724
         if (memcmp(inbuf, outbuf, num_in))
1725
         {
1726
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
1727
                outname);
1728 1729 1730 1731

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1732 1733
                   "   Was %s written with the same maximum"
                   " IDAT chunk size (%d bytes),",
1734 1735
                    inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
1736
                   "\n   filtering heuristic (libpng default), compression");
1737
               fprintf(STDERR,
1738
                   " level (zlib default),\n   and zlib version (%s)?\n\n",
1739 1740 1741
                 ZLIB_VERSION);
               wrote_question = 1;
            }
1742

1743 1744
            FCLOSE(fpin);
            FCLOSE(fpout);
1745

1746 1747 1748 1749 1750 1751 1752
            /* 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);
1753

1754 1755 1756
            else
              return (0);
         }
G
Guy Schalnat 已提交
1757 1758
      }
   }
J
John Bowler 已提交
1759
#endif /* WRITE && WRITE_FILTER */
G
Guy Schalnat 已提交
1760

1761 1762
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1763

1764
   return (0);
G
Guy Schalnat 已提交
1765
}
G
Guy Schalnat 已提交
1766

1767
/* Input and output filenames */
1768
#ifdef RISCOS
1769 1770
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1771
#else
1772 1773
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1774 1775 1776 1777 1778 1779 1780 1781
#endif

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

1782 1783
   png_structp dummy_ptr;

1784
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1785
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1786
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1787
   /* Show the version of libpng used in building the library */
1788
   fprintf(STDERR, " library (%lu):%s",
1789 1790
       (unsigned long)png_access_version_number(),
       png_get_header_version(NULL));
1791

1792
   /* Show the version of libpng used in building the application */
1793
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1794
       PNG_HEADER_VERSION_STRING);
1795 1796

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

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
1812
          "Warning: versions are different between png.h and png.c\n");
1813 1814 1815 1816 1817 1818 1819
      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)
   {
1820
      if (strcmp(argv[1], "-m") == 0)
1821
      {
1822
         multiple = 1;
1823 1824
         status_dots_requested = 0;
      }
1825

1826 1827 1828 1829 1830
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1831
         status_dots_requested = 1;
1832
      }
1833

1834 1835 1836
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1837
         status_dots_requested = 1;
1838 1839
         inname = argv[2];
      }
1840

1841 1842 1843 1844 1845 1846
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
         relaxed = 0;
      }

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

1859
      else
1860
      {
1861
         inname = argv[1];
1862 1863
         status_dots_requested = 0;
      }
1864 1865
   }

1866
   if (multiple == 0 && argc == 3 + verbose)
1867
      outname = argv[2 + verbose];
1868

1869 1870
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
1871
   {
1872 1873 1874 1875 1876 1877 1878 1879
      fprintf(STDERR,
          "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
          argv[0], argv[0]);
      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);
      exit(1);
1880 1881
   }

1882
   if (multiple != 0)
1883 1884
   {
      int i;
1885
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1886
      png_alloc_size_t allocation_now = current_allocation;
1887
#endif
1888
      for (i=2; i<argc; ++i)
1889
      {
1890
         int kerror;
1891
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1892 1893 1894
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
1895
         kerror = test_one_file(argv[i], outname);
1896
         if (kerror == 0)
1897
         {
1898
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1899
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1900
                (unsigned long)zero_samples);
1901
#else
1902
            fprintf(STDERR, " PASS\n");
1903
#endif
1904
#ifdef PNG_TIME_RFC1123_SUPPORTED
1905 1906
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
1907

1908
            tIME_chunk_present = 0;
1909
#endif /* TIME_RFC1123 */
1910
         }
1911

1912 1913
         else
         {
1914 1915
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1916
         }
1917
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1918
         if (allocation_now != current_allocation)
1919 1920
            fprintf(STDERR, "MEMORY ERROR: %lu bytes lost\n",
                (unsigned long)(current_allocation - allocation_now));
1921

1922 1923
         if (current_allocation != 0)
         {
1924 1925
            memory_infop pinfo = pinformation;

1926 1927
            fprintf(STDERR, "MEMORY ERROR: %lu bytes still allocated\n",
                (unsigned long)current_allocation);
1928

1929 1930
            while (pinfo != NULL)
            {
1931
               fprintf(STDERR, " %lu bytes at %p\n",
1932 1933
                   (unsigned long)pinfo->size,
                   pinfo->pointer);
1934
               pinfo = pinfo->next;
1935
            }
1936
         }
1937 1938
#endif
      }
1939
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1940 1941 1942 1943 1944 1945 1946 1947
         fprintf(STDERR, " Current memory allocation: %20lu bytes\n",
             (unsigned long)current_allocation);
         fprintf(STDERR, " Maximum memory allocation: %20lu bytes\n",
             (unsigned long) maximum_allocation);
         fprintf(STDERR, " Total   memory allocation: %20lu bytes\n",
             (unsigned long)total_allocation);
         fprintf(STDERR, "     Number of allocations: %20lu\n",
             (unsigned long)num_allocations);
1948
#endif
1949
   }
1950

1951 1952
   else
   {
1953
      int i;
1954
      for (i = 0; i<3; ++i)
1955
      {
1956
         int kerror;
1957
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1958
         png_alloc_size_t allocation_now = current_allocation;
1959
#endif
1960 1961 1962 1963 1964 1965
         if (i == 1)
            status_dots_requested = 1;

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

1966
         if (i == 0 || verbose == 1 || ierror != 0)
1967
         {
1968
            fprintf(STDERR, "\n Testing %s:", inname);
1969 1970 1971 1972
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
1973

1974
         kerror = test_one_file(inname, outname);
1975

1976
         if (kerror == 0)
1977
         {
1978
            if (verbose == 1 || i == 2)
1979
            {
1980
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1981
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1982
                    (unsigned long)zero_samples);
1983 1984 1985
#else
                fprintf(STDERR, " PASS\n");
#endif
1986
#ifdef PNG_TIME_RFC1123_SUPPORTED
1987 1988
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1989
#endif /* TIME_RFC1123 */
1990
            }
1991
         }
1992

1993 1994
         else
         {
1995
            if (verbose == 0 && i != 2)
1996
            {
1997
               fprintf(STDERR, "\n Testing %s:", inname);
1998 1999 2000 2001
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
2002

2003 2004
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
2005
         }
2006
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2007
         if (allocation_now != current_allocation)
2008 2009
             fprintf(STDERR, "MEMORY ERROR: %lu bytes lost\n",
                 (unsigned long)(current_allocation - allocation_now));
2010

2011 2012
         if (current_allocation != 0)
         {
2013
             memory_infop pinfo = pinformation;
2014

2015 2016
             fprintf(STDERR, "MEMORY ERROR: %lu bytes still allocated\n",
                 (unsigned long)current_allocation);
2017

2018 2019
             while (pinfo != NULL)
             {
2020
                fprintf(STDERR, " %lu bytes at %p\n",
2021
                    (unsigned long)pinfo->size, pinfo->pointer);
2022 2023 2024 2025
                pinfo = pinfo->next;
             }
          }
#endif
2026
       }
2027
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2028 2029 2030 2031 2032 2033 2034 2035
       fprintf(STDERR, " Current memory allocation: %20lu bytes\n",
           (unsigned long)current_allocation);
       fprintf(STDERR, " Maximum memory allocation: %20lu bytes\n",
           (unsigned long)maximum_allocation);
       fprintf(STDERR, " Total   memory allocation: %20lu bytes\n",
           (unsigned long)total_allocation);
       fprintf(STDERR, "     Number of allocations: %20lu\n",
           (unsigned long)num_allocations);
2036
#endif
2037 2038
   }

2039 2040 2041 2042
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
2043
   fprintf(STDERR, " CPU time used = %.3f seconds",
2044
       (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
2045
   fprintf(STDERR, " (decoding %.3f,\n",
2046
       t_decode/(float)CLOCKS_PER_SEC);
2047
   fprintf(STDERR, "        encoding %.3f ,",
2048
       t_encode/(float)CLOCKS_PER_SEC);
2049
   fprintf(STDERR, " other %.3f seconds)\n\n",
2050
       t_misc/(float)CLOCKS_PER_SEC);
2051 2052
#endif

2053
   if (ierror == 0)
2054
      fprintf(STDERR, " libpng passes test\n");
2055

2056
   else
2057
      fprintf(STDERR, " libpng FAILS test\n");
2058

2059 2060 2061
   dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   fprintf(STDERR, " Default limits:\n");
   fprintf(STDERR, "  width_max  = %lu\n",
2062
       (unsigned long) png_get_user_width_max(dummy_ptr));
2063
   fprintf(STDERR, "  height_max = %lu\n",
2064
       (unsigned long) png_get_user_height_max(dummy_ptr));
2065 2066 2067 2068
   if (png_get_chunk_cache_max(dummy_ptr) == 0)
      fprintf(STDERR, "  cache_max  = unlimited\n");
   else
      fprintf(STDERR, "  cache_max  = %lu\n",
2069
          (unsigned long) png_get_chunk_cache_max(dummy_ptr));
2070 2071 2072 2073
   if (png_get_chunk_malloc_max(dummy_ptr) == 0)
      fprintf(STDERR, "  malloc_max = unlimited\n");
   else
      fprintf(STDERR, "  malloc_max = %lu\n",
2074
          (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
2075 2076
   png_destroy_read_struct(&dummy_ptr, NULL, NULL);

2077
   return (int)(ierror != 0);
2078
}
2079 2080 2081 2082 2083
#else
int
main(void)
{
   fprintf(STDERR,
2084
       " test ignored because libpng was not built with read support\n");
2085
   /* And skip this test */
2086
   return SKIP;
2087 2088
}
#endif
2089

2090
/* Generate a compiler error if there is an old png.h in the search path. */
2091
typedef png_libpng_version_1_6_25beta01 Your_png_h_is_not_version_1_6_25beta01;