pngtest.c 58.4 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.19 [November 12, 2015]
5
 * Copyright (c) 1998-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
/* Known chunks that exist in pngtest.png must be supported or pngtest will fail
 * simply as a result of re-ordering them.  This may be fixed in 1.7
48 49 50 51 52
 *
 * pngtest allocates a single row buffer for each row and overwrites it,
 * therefore if the write side doesn't support the writing of interlaced images
 * nothing can be done for an interlaced image (and the code below will fail
 * horribly trying to write extra data after writing garbage).
53 54 55 56 57 58 59 60 61 62
 */
#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 &&\
63
   defined PNG_READ_sPLT_SUPPORTED &&\
64 65 66
   defined PNG_READ_sRGB_SUPPORTED &&\
   defined PNG_READ_tEXt_SUPPORTED &&\
   defined PNG_READ_tIME_SUPPORTED &&\
67 68 69 70 71 72 73 74
   defined PNG_READ_zTXt_SUPPORTED &&\
   defined PNG_WRITE_INTERLACING_SUPPORTED

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

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

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

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

91 92 93 94 95 96 97 98 99
#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
100

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

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

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

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

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

124
static int verbose = 0;
125
static int strict = 0;
126 127 128 129
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 */
130

131 132 133 134 135
/* 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

136 137 138 139 140 141 142 143 144 145 146
/* 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))

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

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

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

165
   status_dots--;
166

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

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

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

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


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

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

207
static png_uint_32 zero_samples;
208

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

216
   /* Contents of row_info:
217 218 219 220 221 222 223 224
    *  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)
    */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

443
   ++warning_count;
444

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

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

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

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

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

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

/* Allocate memory.  For reasonable files, size should never exceed
473
 * 64K.  However, zlib may allocate more than 64K if you don't tell
474 475 476 477 478 479 480
 * 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.
 */
481 482
typedef struct memory_information
{
483
   png_alloc_size_t          size;
484
   png_voidp                 pointer;
485
   struct memory_information *next;
486
} memory_information;
487
typedef memory_information *memory_infop;
488 489 490 491

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   /* Unlink the element from the list. */
569
   if (pinformation != NULL)
570
   {
571
      memory_infop *ppinfo = &pinformation;
572

573 574
      for (;;)
      {
575
         memory_infop pinfo = *ppinfo;
576

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

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

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

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

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

612

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

   png_byte vpag_chunk_data[9];

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

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);
   }
}
784 785
#endif /* WRITE */
#else /* !READ_USER_CHUNKS */
786
#  define write_chunks(pp,loc) ((void)0)
787 788 789
#endif
/* END of code to demonstrate user chunk support */

790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
/* START of code to check that libpng has the required text support; this only
 * checks for the write support because if read support is missing the chunk
 * will simply not be reported back to pngtest.
 */
#ifdef PNG_TEXT_SUPPORTED
static void
pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr,
   int num_text)
{
   while (num_text > 0)
   {
      switch (text_ptr[--num_text].compression)
      {
         case PNG_TEXT_COMPRESSION_NONE:
            break;

         case PNG_TEXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_zTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         default:
            /* This is an error */
            png_error(png_ptr, "invalid text chunk compression field");
            break;
      }
   }
}
#endif
/* END of code to check that libpng has the required text support */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1003
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1004
   {
1005
      int i;
1006

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

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

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

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

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

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

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

            case PNG_INTERLACE_ADAM7:
               num_pass = 7;
                break;

            default:
                png_error(read_ptr, "invalid interlace type");
                /*NOT REACHED*/
         }
1077
#endif
A
Andreas Dilger 已提交
1078 1079
      }
   }
1080

1081 1082
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
1083
   {
1084
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1085
         blue_y;
1086

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

1096
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1097
   {
1098
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1099

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

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

1123
      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0)
1124 1125 1126
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1127 1128
#endif /* Floating point */
#endif /* Fixed point */
1129

1130
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1131
   {
1132
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1133
      png_bytep profile;
1134
      png_uint_32 proflen;
1135
      int compression_type;
A
Andreas Dilger 已提交
1136

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

1146
#ifdef PNG_sRGB_SUPPORTED
1147
   {
1148
      int intent;
1149

1150
      if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
1151 1152
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1153
#endif
1154

1155 1156 1157 1158
   {
      png_colorp palette;
      int num_palette;

1159
      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
1160 1161
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1162

1163
#ifdef PNG_bKGD_SUPPORTED
1164 1165 1166
   {
      png_color_16p background;

1167
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1168 1169 1170 1171 1172
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1173

1174
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1175
   {
A
Andreas Dilger 已提交
1176 1177
      png_uint_16p hist;

1178
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1179
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1180
   }
A
Andreas Dilger 已提交
1181
#endif
1182

1183
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1184
   {
1185
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1186
      int unit_type;
G
Guy Schalnat 已提交
1187

1188
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1189
          &unit_type) != 0)
A
Andreas Dilger 已提交
1190 1191 1192 1193 1194
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1195

1196
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1197 1198 1199 1200 1201 1202 1203
   {
      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,
1204
         &nparams, &units, &params) != 0)
A
Andreas Dilger 已提交
1205 1206 1207 1208 1209 1210
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1211

1212
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1213 1214 1215 1216
   {
      png_uint_32 res_x, res_y;
      int unit_type;

1217 1218
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1219 1220 1221
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1222

1223
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1224
   {
1225
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1226

1227
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1228
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1229
   }
1230
#endif
1231

1232
#ifdef PNG_sCAL_SUPPORTED
1233 1234
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1235
   {
1236
      int unit;
1237
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1238

1239
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1240
         &scal_height) != 0)
G
Guy Schalnat 已提交
1241
      {
1242
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1243 1244 1245
      }
   }
#else
1246
#ifdef PNG_FIXED_POINT_SUPPORTED
1247
   {
1248
      int unit;
1249
      png_charp scal_width, scal_height;
1250

1251
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1252
          &scal_height) != 0)
1253
      {
1254 1255
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1256 1257
      }
   }
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
#endif /* FIXED_POINT */
#endif /* FLOATING_POINT */
#endif /* sCAL */

#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);
       }
   }
#endif /* sPLT */

1274
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1275 1276 1277 1278 1279 1280
   {
      png_textp text_ptr;
      int num_text;

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

1283 1284
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1285
         if (verbose != 0)
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
         {
            int i;

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

A
Andreas Dilger 已提交
1297 1298 1299
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
1300 1301
#endif /* TEXT */

1302
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1303 1304 1305
   {
      png_timep mod_time;

1306
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1307 1308
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1309
#ifdef PNG_TIME_RFC1123_SUPPORTED
1310
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1311
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1312 1313

         else
1314 1315 1316 1317
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1318

1319
         tIME_chunk_present++;
1320
#endif /* TIME_RFC1123 */
1321
      }
A
Andreas Dilger 已提交
1322
   }
1323 1324
#endif /* tIME */

1325
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1326
   {
1327
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1328
      int num_trans;
1329
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1330

1331
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1332
         &trans_color) != 0)
A
Andreas Dilger 已提交
1333
      {
1334
         int sample_max = (1 << bit_depth);
1335
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1336
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1337
             (int)trans_color->gray > sample_max) ||
1338
             (color_type == PNG_COLOR_TYPE_RGB &&
1339 1340 1341
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1342
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1343
               trans_color);
A
Andreas Dilger 已提交
1344 1345
      }
   }
1346 1347
#endif /* tRNS */

1348
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1349 1350
   {
      png_unknown_chunkp unknowns;
1351
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1352
         &unknowns);
1353

1354
      if (num_unknowns != 0)
1355 1356 1357
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1358
#if PNG_LIBPNG_VER < 10600
1359
         /* Copy the locations from the read_info_ptr.  The automatically
1360 1361
          * 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).
1362
          */
1363 1364 1365 1366 1367 1368 1369
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
                unknowns[i].location);
         }
#endif
1370 1371 1372
      }
   }
#endif
A
Andreas Dilger 已提交
1373

1374
#ifdef PNG_WRITE_SUPPORTED
1375
   pngtest_debug("Writing info struct");
1376

1377 1378 1379 1380
   /* 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);
1381

1382
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1383

1384
   png_write_info(write_ptr, write_info_ptr);
1385

1386
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1387
#endif
A
Andreas Dilger 已提交
1388

1389
#ifdef SINGLE_ROWBUF_ALLOC
1390
   pngtest_debug("Allocating row buffer...");
1391
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1392
      png_get_rowbytes(read_ptr, read_info_ptr));
1393

1394
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1395
#endif /* SINGLE_ROWBUF_ALLOC */
1396
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1397

1398
#ifdef PNG_READ_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
1399
   num_pass = png_set_interlace_handling(read_ptr);
1400 1401
   if (png_set_interlace_handling(write_ptr) != num_pass)
      png_error(write_ptr, "png_set_interlace_handling: inconsistent num_pass");
1402
#endif
A
Andreas Dilger 已提交
1403

1404 1405 1406 1407 1408
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1409 1410
   for (pass = 0; pass < num_pass; pass++)
   {
1411
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1412 1413
      for (y = 0; y < height; y++)
      {
1414
#ifndef SINGLE_ROWBUF_ALLOC
1415
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1416

1417 1418
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1419

1420 1421
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
            (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1422

1423
#endif /* !SINGLE_ROWBUF_ALLOC */
1424
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1425 1426

#ifdef PNG_WRITE_SUPPORTED
1427 1428 1429 1430 1431
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1432
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1433 1434 1435 1436 1437
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1438
#endif /* WRITE */
1439 1440

#ifndef SINGLE_ROWBUF_ALLOC
1441
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1442
         png_free(read_ptr, row_buf);
1443
         row_buf = NULL;
1444
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1445 1446 1447
      }
   }

1448 1449 1450 1451 1452 1453 1454
#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
1455 1456
#endif

1457
   pngtest_debug("Reading and writing end_info data");
1458

A
Andreas Dilger 已提交
1459
   png_read_end(read_ptr, end_info_ptr);
1460
#ifdef PNG_TEXT_SUPPORTED
1461 1462 1463 1464 1465 1466
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1467
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1468 1469 1470

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1471
         if (verbose != 0)
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
         {
            int i;

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

1483 1484 1485 1486
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1487
#ifdef PNG_tIME_SUPPORTED
1488 1489 1490
   {
      png_timep mod_time;

1491
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1492 1493
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1494
#ifdef PNG_TIME_RFC1123_SUPPORTED
1495
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1496
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1497 1498

         else
1499 1500 1501 1502
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1503

1504
         tIME_chunk_present++;
1505
#endif /* TIME_RFC1123 */
1506 1507
      }
   }
1508
#endif
1509
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1510 1511
   {
      png_unknown_chunkp unknowns;
1512
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1513
         &unknowns);
1514

1515
      if (num_unknowns != 0)
1516 1517 1518
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1519
#if PNG_LIBPNG_VER < 10600
1520
         /* Copy the locations from the read_info_ptr.  The automatically
1521 1522
          * 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).
1523
          */
1524 1525 1526 1527 1528 1529 1530
         {
            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
1531 1532
      }
   }
1533
#endif
1534

1535
#ifdef PNG_WRITE_SUPPORTED
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
#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);

1552
   png_write_end(write_ptr, write_end_info_ptr);
1553
#endif
1554

1555
#ifdef PNG_EASY_ACCESS_SUPPORTED
1556
   if (verbose != 0)
1557 1558 1559 1560
   {
      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);
1561
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1562
         (unsigned long)iwidth, (unsigned long)iheight);
1563 1564
   }
#endif
G
Guy Schalnat 已提交
1565

1566
   pngtest_debug("Destroying data structs");
1567
#ifdef SINGLE_ROWBUF_ALLOC
1568
   pngtest_debug("destroying row_buf for read_ptr");
1569
   png_free(read_ptr, row_buf);
1570
   row_buf = NULL;
1571
#endif /* SINGLE_ROWBUF_ALLOC */
1572
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1573
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1574
#ifdef PNG_WRITE_SUPPORTED
1575
   pngtest_debug("destroying write_end_info_ptr");
1576
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1577
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1578
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1579
#endif
1580
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1581

1582 1583
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1584

1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618
   /* Summarize any warnings or errors and in 'strict' mode fail the test.
    * Unsupported chunks can result in warnings, in that case ignore the strict
    * setting, otherwise fail the test on warnings as well as errors.
    */
   if (error_count > 0)
   {
      /* We don't really expect to get here because of the setjmp handling
       * above, but this is safe.
       */
      fprintf(STDERR, "\n  %s: %d libpng errors found (%d warnings)",
         inname, error_count, warning_count);

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

#  ifdef PNG_WRITE_SUPPORTED
      /* If there we no write support nothing was written! */
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
            inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
         inname, warning_count);

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

1619
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1620
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1621
   {
G
Guy Schalnat 已提交
1622
      fprintf(STDERR, "Could not find file %s\n", inname);
1623
      return (1);
G
Guy Schalnat 已提交
1624 1625
   }

A
Andreas Dilger 已提交
1626
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1627
   {
G
Guy Schalnat 已提交
1628
      fprintf(STDERR, "Could not find file %s\n", outname);
1629
      FCLOSE(fpin);
1630
      return (1);
G
Guy Schalnat 已提交
1631
   }
A
Andreas Dilger 已提交
1632

1633
#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
1634
   if (interlace_preserved != 0) /* else the files will be changed */
G
Guy Schalnat 已提交
1635
   {
1636
      for (;;)
1637
      {
1638
         static int wrote_question = 0;
1639 1640 1641
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];

1642 1643
         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1644

1645
         if (num_in != num_out)
1646
         {
1647 1648
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
                    inname, outname);
1649

1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661
            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;
            }
1662

1663 1664
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1665

1666 1667
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1668

1669 1670 1671
            else
              return (0);
         }
1672

1673
         if (num_in == 0)
1674
            break;
1675

1676
         if (memcmp(inbuf, outbuf, num_in))
1677
         {
1678 1679 1680 1681 1682 1683
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
               outname);

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1684
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1685 1686 1687 1688 1689 1690 1691 1692
                    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;
            }
1693

1694 1695
            FCLOSE(fpin);
            FCLOSE(fpout);
1696

1697 1698 1699 1700 1701 1702 1703
            /* 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);
1704

1705 1706 1707
            else
              return (0);
         }
G
Guy Schalnat 已提交
1708 1709
      }
   }
1710
#endif /* WRITE */
G
Guy Schalnat 已提交
1711

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

1715
   return (0);
G
Guy Schalnat 已提交
1716
}
G
Guy Schalnat 已提交
1717

1718
/* Input and output filenames */
1719
#ifdef RISCOS
1720 1721
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1722
#else
1723 1724
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1725 1726 1727 1728 1729 1730 1731 1732
#endif

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

1733 1734
   png_structp dummy_ptr;

1735
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1736
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1737
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1738
   /* Show the version of libpng used in building the library */
1739 1740
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1741
      png_get_header_version(NULL));
1742

1743
   /* Show the version of libpng used in building the application */
1744
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1745
      PNG_HEADER_VERSION_STRING);
1746 1747

   /* Do some consistency checking on the memory allocation settings, I'm
1748 1749 1750 1751
    * 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
    */
1752
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1753
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1754
#endif
1755
   /* I think the following can happen. */
1756
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1757
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1758
#endif
1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770

   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)
   {
1771
      if (strcmp(argv[1], "-m") == 0)
1772
      {
1773
         multiple = 1;
1774 1775
         status_dots_requested = 0;
      }
1776

1777 1778 1779 1780 1781
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1782
         status_dots_requested = 1;
1783
      }
1784

1785 1786 1787
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1788
         status_dots_requested = 1;
1789 1790
         inname = argv[2];
      }
1791

1792 1793 1794 1795 1796 1797
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1798 1799 1800 1801 1802 1803 1804 1805 1806 1807
         relaxed = 0;
      }

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

1810
      else
1811
      {
1812
         inname = argv[1];
1813 1814
         status_dots_requested = 0;
      }
1815 1816
   }

1817
   if (multiple == 0 && argc == 3 + verbose)
1818
     outname = argv[2 + verbose];
1819

1820 1821
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
1822
   {
1823 1824
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1825
        argv[0], argv[0]);
1826 1827 1828 1829
     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);
1830 1831 1832
     exit(1);
   }

1833
   if (multiple != 0)
1834 1835
   {
      int i;
1836
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1837 1838
      int allocation_now = current_allocation;
#endif
1839
      for (i=2; i<argc; ++i)
1840
      {
1841
         int kerror;
1842
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1843 1844 1845
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
1846
         kerror = test_one_file(argv[i], outname);
1847
         if (kerror == 0)
1848
         {
1849 1850 1851
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1852
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1853
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1854
               (unsigned long)zero_samples);
1855
#else
1856
            fprintf(STDERR, " PASS\n");
1857
#endif
1858
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1859
            for (k = 0; k<256; k++)
1860
               if (filters_used[k] != 0)
1861
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1862
                     k, (unsigned long)filters_used[k]);
1863
#endif
1864
#ifdef PNG_TIME_RFC1123_SUPPORTED
1865 1866
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
1867

1868
            tIME_chunk_present = 0;
1869
#endif /* TIME_RFC1123 */
1870
         }
1871

1872 1873
         else
         {
1874 1875
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1876
         }
1877
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1878 1879
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1880
               current_allocation - allocation_now);
1881

1882 1883
         if (current_allocation != 0)
         {
1884 1885 1886 1887
            memory_infop pinfo = pinformation;

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

1889 1890
            while (pinfo != NULL)
            {
1891
               fprintf(STDERR, " %lu bytes at %p\n",
1892
                 (unsigned long)pinfo->size,
1893
                 pinfo->pointer);
1894
               pinfo = pinfo->next;
1895
            }
1896
         }
1897 1898
#endif
      }
1899
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1900
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1901
            current_allocation);
1902
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1903
            maximum_allocation);
1904 1905 1906 1907
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1908
#endif
1909
   }
1910

1911 1912
   else
   {
1913
      int i;
1914
      for (i = 0; i<3; ++i)
1915
      {
1916
         int kerror;
1917
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1918 1919
         int allocation_now = current_allocation;
#endif
1920 1921 1922 1923 1924 1925
         if (i == 1)
            status_dots_requested = 1;

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

1926
         if (i == 0 || verbose == 1 || ierror != 0)
1927
         {
1928
            fprintf(STDERR, "\n Testing %s:", inname);
1929 1930 1931 1932
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
1933

1934
         kerror = test_one_file(inname, outname);
1935

1936
         if (kerror == 0)
1937
         {
1938
            if (verbose == 1 || i == 2)
1939
            {
1940
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1941
                int k;
1942
#endif
1943
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1944
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1945
                   (unsigned long)zero_samples);
1946 1947 1948
#else
                fprintf(STDERR, " PASS\n");
#endif
1949
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1950
                for (k = 0; k<256; k++)
1951
                   if (filters_used[k] != 0)
1952
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1953
                         k, (unsigned long)filters_used[k]);
1954
#endif
1955
#ifdef PNG_TIME_RFC1123_SUPPORTED
1956 1957
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1958
#endif /* TIME_RFC1123 */
1959
            }
1960
         }
1961

1962 1963
         else
         {
1964
            if (verbose == 0 && i != 2)
1965
            {
1966
               fprintf(STDERR, "\n Testing %s:", inname);
1967 1968 1969 1970
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
1971

1972 1973
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1974
         }
1975
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1976 1977
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1978
               current_allocation - allocation_now);
1979

1980 1981
         if (current_allocation != 0)
         {
1982
             memory_infop pinfo = pinformation;
1983

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

1987 1988
             while (pinfo != NULL)
             {
1989 1990
                fprintf(STDERR, " %lu bytes at %p\n",
                   (unsigned long)pinfo->size, pinfo->pointer);
1991 1992 1993 1994
                pinfo = pinfo->next;
             }
          }
#endif
1995
       }
1996
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1997
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1998
          current_allocation);
1999
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
2000
          maximum_allocation);
2001 2002 2003 2004
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
2005
#endif
2006 2007
   }

2008 2009 2010 2011
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
2012
   fprintf(STDERR, " CPU time used = %.3f seconds",
2013
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
2014
   fprintf(STDERR, " (decoding %.3f,\n",
2015
      t_decode/(float)CLOCKS_PER_SEC);
2016
   fprintf(STDERR, "        encoding %.3f ,",
2017
      t_encode/(float)CLOCKS_PER_SEC);
2018
   fprintf(STDERR, " other %.3f seconds)\n\n",
2019 2020 2021
      t_misc/(float)CLOCKS_PER_SEC);
#endif

2022
   if (ierror == 0)
2023
      fprintf(STDERR, " libpng passes test\n");
2024

2025
   else
2026
      fprintf(STDERR, " libpng FAILS test\n");
2027

2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
   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);

2046
   return (int)(ierror != 0);
2047
}
2048 2049 2050 2051 2052 2053
#else
int
main(void)
{
   fprintf(STDERR,
      " test ignored because libpng was not built with read support\n");
2054
   /* And skip this test */
2055
   return PNG_LIBPNG_VER < 10600 ? 0 : 77;
2056 2057
}
#endif
2058

2059
/* Generate a compiler error if there is an old png.h in the search path. */
2060
typedef png_libpng_version_1_6_20beta01 Your_png_h_is_not_version_1_6_20beta01;