pngtest.c 50.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.5.6 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2011 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

G
[devel]  
Glenn Randers-Pehrson 已提交
36
#include "zlib.h"
37
#include "png.h"
38 39 40 41
/* Copied from pngpriv.h but only used in error messages below. */
#ifndef PNG_ZBUF_SIZE
#  define PNG_ZBUF_SIZE 8192
#endif
42 43
#  include <stdio.h>
#  include <stdlib.h>
44
#  include <string.h>
45
#  define FCLOSE(file) fclose(file)
46

47
#ifndef PNG_STDIO_SUPPORTED
48
typedef FILE                * png_FILE_p;
49 50
#endif

51
/* Makes pngtest verbose so we can find problems. */
A
Andreas Dilger 已提交
52
#ifndef PNG_DEBUG
53 54 55
#  define PNG_DEBUG 0
#endif

56 57 58 59 60 61 62 63 64
#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
65

66
#if !PNG_DEBUG
67
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
68
#endif
A
Andreas Dilger 已提交
69

G
[devel]  
Glenn Randers-Pehrson 已提交
70 71 72 73 74 75 76 77 78 79 80
/* The code uses memcmp and memcpy on large objects (typically row pointers) so
 * it is necessary to do soemthing special on certain architectures, note that
 * the actual support for this was effectively removed in 1.4, so only the
 * memory remains in this program:
 */
#define CVT_PTR(ptr)         (ptr)
#define CVT_PTR_NOCHECK(ptr) (ptr)
#define png_memcmp  memcmp
#define png_memcpy  memcpy
#define png_memset  memset

81 82 83 84
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

85
#ifndef PNG_FLOATING_POINT_SUPPORTED
86 87 88
#undef PNGTEST_TIMING
#endif

89 90 91 92 93
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

94
#ifdef PNG_TIME_RFC1123_SUPPORTED
95
#define PNG_tIME_STRING_LENGTH 29
96
static int tIME_chunk_present = 0;
97
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
98 99
#endif

100
static int verbose = 0;
101
static int strict = 0;
102

103
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
104

G
Guy Schalnat 已提交
105 106 107 108
#ifdef __TURBOC__
#include <mem.h>
#endif

109
/* Defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
110
/*  #define STDERR stderr  */
111
#define STDERR stdout   /* For DOS */
G
Guy Schalnat 已提交
112

113 114 115 116 117
/* 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

118
/* Example of using row callbacks to make a simple progress meter */
119 120 121
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
122

123
void PNGCBAPI
124
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
125
void PNGCBAPI
126
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
127
{
128 129
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
130

131 132 133 134 135 136
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
137

138
   status_dots--;
139

140 141 142 143 144
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
145

146
   fprintf(stdout, "r");
147
}
148

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

157
   fprintf(stdout, "w");
158 159 160
}


161
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
162
/* Example of using user transform callback (we don't transform anything,
163 164 165
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
166
static png_uint_32 filters_used[256];
167
void PNGCBAPI
168
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
169
void PNGCBAPI
170 171
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
172
   if (png_ptr != NULL && row_info != NULL)
173
      ++filters_used[*(data - 1)];
174 175 176
}
#endif

177
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
178
/* Example of using user transform callback (we don't transform anything,
179 180
 * but merely count the zero samples)
 */
181

182
static png_uint_32 zero_samples;
183

184
void PNGCBAPI
185
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
186
void PNGCBAPI
187
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
188 189
{
   png_bytep dp = data;
190 191
   if (png_ptr == NULL)
      return;
192

193
   /* Contents of row_info:
194 195 196 197 198 199 200 201
    *  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)
    */

202
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
203

204
    if (row_info->color_type == 0 || row_info->color_type == 3)
205
    {
206
       int pos = 0;
207
       png_uint_32 n, nstop;
208

209
       for (n = 0, nstop=row_info->width; n<nstop; n++)
210
       {
211
          if (row_info->bit_depth == 1)
212
          {
213 214
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
215

216
             if (pos == 8)
217
             {
218
                pos = 0;
219 220
                dp++;
             }
221
          }
222

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

228
             if (pos == 8)
229
             {
230
                pos = 0;
231 232
                dp++;
             }
233
          }
234

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

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

247
          if (row_info->bit_depth == 8)
248 249
             if (*dp++ == 0)
                zero_samples++;
250

251
          if (row_info->bit_depth == 16)
252
          {
253 254
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
255 256 257 258
             dp+=2;
          }
       }
    }
259
    else /* Other color types */
260
    {
261
       png_uint_32 n, nstop;
262 263
       int channel;
       int color_channels = row_info->channels;
264
       if (row_info->color_type > 3)color_channels--;
265

266
       for (n = 0, nstop=row_info->width; n<nstop; n++)
267 268 269
       {
          for (channel = 0; channel < color_channels; channel++)
          {
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
          if (row_info->color_type > 3)
283 284
          {
             dp++;
285 286
             if (row_info->bit_depth == 16)
                dp++;
287 288 289 290
          }
       }
    }
}
291
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
292

293
static int wrote_question = 0;
294

295
#ifndef PNG_STDIO_SUPPORTED
296
/* START of code to validate stdio-free compilation */
297 298 299 300 301 302 303
/* 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.
 */
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 341 342 343 344 345 346
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op)
{
   png_uint_32 io_state = png_get_io_state(png_ptr);
   int err = 0;

   /* Check if the current operation (reading / writing) is as expected. */
   if ((io_state & PNG_IO_MASK_OP) != io_op)
      png_error(png_ptr, "Incorrect operation in I/O state");

   /* Check if the buffer size specific to the current location
    * (file signature / header / data / crc) is as expected.
    */
   switch (io_state & PNG_IO_MASK_LOC)
   {
   case PNG_IO_SIGNATURE:
      if (data_length > 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_HDR:
      if (data_length != 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_DATA:
      break;  /* no restrictions here */
   case PNG_IO_CHUNK_CRC:
      if (data_length != 4)
         err = 1;
      break;
   default:
      err = 1;  /* uninitialized */
   }
   if (err)
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

347
#ifndef USE_FAR_KEYWORD
348
static void PNGCBAPI
349
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
350
{
351 352
   png_size_t check = 0;
   png_voidp io_ptr;
353 354 355 356

   /* 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.
    */
357 358 359 360 361
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
362

363 364
   if (check != length)
   {
365
      png_error(png_ptr, "Read Error");
366
   }
367 368 369 370

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
371
}
G
Guy Schalnat 已提交
372
#else
373
/* This is the model-independent version. Since the standard I/O library
374 375 376
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
377

378 379
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
380

381
static void PNGCBAPI
382
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
383
{
384
   png_size_t check;
385
   png_byte *n_data;
386
   png_FILE_p io_ptr;
387 388 389

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
390
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
391 392
   if ((png_bytep)n_data == data)
   {
393
      check = fread(n_data, 1, length, io_ptr);
394 395 396 397 398 399 400
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
401

402 403 404
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
405
         err = fread(buf, 1, 1, io_ptr);
406
         png_memcpy(data, buf, read); /* Copy far buffer to near buffer */
407
         if (err != read)
408 409 410 411 412 413 414 415
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
416

417
   if (check != length)
418 419 420 421 422
      png_error(png_ptr, "Read Error");

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
423
}
424
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
425

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

435
/* This is the function that does the actual writing of data.  If you are
436 437 438 439
 * 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.
 */
440
#ifndef USE_FAR_KEYWORD
441
static void PNGCBAPI
442
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
443
{
444
   png_size_t check;
445

446
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
447

448 449 450 451
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
452 453 454 455

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
456 457
}
#else
458
/* This is the model-independent version. Since the standard I/O library
459 460 461 462 463 464 465
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/

#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)

466
static void PNGCBAPI
467
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
468
{
469
   png_size_t check;
470
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
471
   png_FILE_p io_ptr;
472 473 474

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
475
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
476

477 478
   if ((png_bytep)near_data == data)
   {
479
      check = fwrite(near_data, 1, length, io_ptr);
480
   }
481

482 483 484 485 486 487
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
488

489 490 491
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
492
         png_memcpy(buf, data, written); /* Copy far buffer to near buffer */
493
         err = fwrite(buf, 1, written, io_ptr);
494 495 496 497 498 499 500 501 502
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
503

504 505 506 507
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
508 509 510 511

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
512
}
513
#endif /* USE_FAR_KEYWORD */
514 515 516 517 518 519

/* 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.
 */
520
static void PNGCBAPI
521
pngtest_warning(png_structp png_ptr, png_const_charp message)
522 523
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
524 525
   char *test;
   test = png_get_error_ptr(png_ptr);
526

527 528
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
529

530 531
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
532 533 534 535 536 537 538
}

/* 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().
 */
539
static void PNGCBAPI
540
pngtest_error(png_structp png_ptr, png_const_charp message)
541
{
542
   pngtest_warning(png_ptr, message);
543
   /* We can return because png_error calls the default handler, which is
544 545
    * actually OK in this case.
    */
546
}
547
#endif /* !PNG_STDIO_SUPPORTED */
548 549
/* END of code to validate stdio-free compilation */

550
/* START of code to validate memory allocation and deallocation */
551
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
552 553

/* Allocate memory.  For reasonable files, size should never exceed
554 555 556 557 558 559 560 561
 * 64K.  However, zlib may allocate more then 64K if you don't tell
 * it not to.  See zconf.h and png.h for more information.  zlib does
 * need to allocate exactly 64K, so whatever you call here must
 * have the ability to do that.
 *
 * This piece of code can be compiled to validate max 64K allocations
 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
 */
562 563
typedef struct memory_information
{
564
   png_alloc_size_t          size;
565
   png_voidp                 pointer;
566 567 568 569 570 571 572
   struct memory_information FAR *next;
} memory_information;
typedef memory_information FAR *memory_infop;

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
573 574
static int total_allocation = 0;
static int num_allocations = 0;
575

576 577 578
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));
579 580

png_voidp
581
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
582
{
583

584
   /* png_malloc has already tested for NULL; png_create_struct calls
585 586
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
587

588
   if (size == 0)
589
      return (NULL);
590 591 592 593

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
594
      /* Disable malloc_fn and free_fn */
595
      memory_infop pinfo;
596
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
597 598
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
599 600
      pinfo->size = size;
      current_allocation += size;
601 602
      total_allocation += size;
      num_allocations ++;
603

604 605
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
606

607
      pinfo->pointer = png_malloc(png_ptr, size);
608
      /* Restore malloc_fn and free_fn */
609

610 611
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
612

613 614 615 616
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
617
         png_error(png_ptr,
618
           "out of memory in pngtest->png_debug_malloc");
619
      }
620

621 622 623 624
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
625

626
      if (verbose)
627
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
628
            pinfo->pointer);
629

630
      return (png_voidp)(pinfo->pointer);
631 632 633 634
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
635
void PNGCBAPI
636
png_debug_free(png_structp png_ptr, png_voidp ptr)
637 638
{
   if (png_ptr == NULL)
639
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
640

641 642
   if (ptr == 0)
   {
643 644 645 646 647 648 649 650 651
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
      memory_infop FAR *ppinfo = &pinformation;
652

653 654
      for (;;)
      {
655
         memory_infop pinfo = *ppinfo;
656

657 658
         if (pinfo->pointer == ptr)
         {
659 660 661 662 663
            *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
664
               the memory that is to be freed. */
665
            png_memset(ptr, 0x55, pinfo->size);
666
            png_free_default(png_ptr, pinfo);
667
            pinfo = NULL;
668 669
            break;
         }
670

671 672
         if (pinfo->next == NULL)
         {
673
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
674 675
            break;
         }
676

677 678 679 680 681
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
682
   if (verbose)
683
      printf("Freeing %p\n", ptr);
684

685
   png_free_default(png_ptr, ptr);
686
   ptr = NULL;
687
}
688
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
689 690
/* END of code to test memory allocation/deallocation */

691 692

/* Demonstration of user chunk support of the sTER and vpAg chunks */
693
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
694

695
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
696 697 698 699
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

700 701 702 703
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
704 705
     */

706
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
707 708
   png_unknown_chunkp chunk)
{
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
   png_uint_32
     *my_user_chunk_data;

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

732 733
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
734

735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
         my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
         my_user_chunk_data[0]=chunk->data[0]+1;
         return (1);
      }

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

   my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);

   my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data);
   my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4);
   my_user_chunk_data[3]=(png_uint_32)chunk->data[8];

   return (1);
756 757 758 759 760

}
#endif
/* END of code to demonstrate user chunk support */

761
/* Test one file */
762 763
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
764
{
765 766
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
767 768 769 770 771 772 773 774 775 776 777
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
G
Guy Schalnat 已提交
778
   png_bytep row_buf;
G
Guy Schalnat 已提交
779
   png_uint_32 y;
A
Andreas Dilger 已提交
780 781 782
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
783
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
784
#ifdef USE_FAR_KEYWORD
785
   jmp_buf tmp_jmpbuf;
786
#endif
787
#endif
788

789
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
790

791
   row_buf = NULL;
G
Guy Schalnat 已提交
792

A
Andreas Dilger 已提交
793
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
794 795
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
796
      return (1);
G
Guy Schalnat 已提交
797 798
   }

A
Andreas Dilger 已提交
799
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
800
   {
G
Guy Schalnat 已提交
801
      fprintf(STDERR, "Could not open output file %s\n", outname);
802
      FCLOSE(fpin);
803
      return (1);
G
Guy Schalnat 已提交
804 805
   }

806
   pngtest_debug("Allocating read and write structures");
807
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
808 809
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
810
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
811
#else
812 813
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
814
#endif
815
#ifndef PNG_STDIO_SUPPORTED
816 817
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
818
#endif
819

820
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
821 822 823 824 825 826
   user_chunk_data[0] = 0;
   user_chunk_data[1] = 0;
   user_chunk_data[2] = 0;
   user_chunk_data[3] = 0;
   png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
     read_user_chunk_callback);
827

828
#endif
829
#ifdef PNG_WRITE_SUPPORTED
830
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
831 832 833
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
834
#else
835 836
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
837
#endif
838
#ifndef PNG_STDIO_SUPPORTED
839 840
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
841
#endif
842
#endif
843
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
844
   read_info_ptr = png_create_info_struct(read_ptr);
845
   end_info_ptr = png_create_info_struct(read_ptr);
846 847
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
848
   write_end_info_ptr = png_create_info_struct(write_ptr);
849
#endif
G
Guy Schalnat 已提交
850

851
#ifdef PNG_SETJMP_SUPPORTED
852
   pngtest_debug("Setting jmpbuf for read struct");
A
Andreas Dilger 已提交
853
#ifdef USE_FAR_KEYWORD
854
   if (setjmp(tmp_jmpbuf))
A
Andreas Dilger 已提交
855
#else
856
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
857
#endif
G
Guy Schalnat 已提交
858
   {
859
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
860 861
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
862
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
863
#ifdef PNG_WRITE_SUPPORTED
864
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
865
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
866
#endif
867 868
      FCLOSE(fpin);
      FCLOSE(fpout);
869
      return (1);
G
Guy Schalnat 已提交
870
   }
871
#ifdef USE_FAR_KEYWORD
872
   png_memcpy(png_jmpbuf(read_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
873
#endif
A
Andreas Dilger 已提交
874

875
#ifdef PNG_WRITE_SUPPORTED
876
   pngtest_debug("Setting jmpbuf for write struct");
A
Andreas Dilger 已提交
877
#ifdef USE_FAR_KEYWORD
878

879
   if (setjmp(tmp_jmpbuf))
A
Andreas Dilger 已提交
880
#else
881
   if (setjmp(png_jmpbuf(write_ptr)))
A
Andreas Dilger 已提交
882
#endif
G
Guy Schalnat 已提交
883
   {
884
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
885
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
886
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
887
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
888
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
889
#endif
890 891
      FCLOSE(fpin);
      FCLOSE(fpout);
892
      return (1);
G
Guy Schalnat 已提交
893
   }
894

A
Andreas Dilger 已提交
895
#ifdef USE_FAR_KEYWORD
896
   png_memcpy(png_jmpbuf(write_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
897
#endif
898
#endif
A
Andreas Dilger 已提交
899
#endif
900

901
   pngtest_debug("Initializing input and output streams");
902
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
903
   png_init_io(read_ptr, fpin);
904
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
905
   png_init_io(write_ptr, fpout);
906
#  endif
907
#else
908
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
909
#  ifdef PNG_WRITE_SUPPORTED
910
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
911
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
912
      pngtest_flush);
913
#    else
914
      NULL);
915 916
#    endif
#  endif
917
#endif
918

919
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
920 921
   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
    * This is here just to make pngtest replicate the results from libpng
922
    * versions prior to 1.5.4, and to test this new API.
923
    */
924 925 926
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

927
   if (status_dots_requested == 1)
928
   {
929
#ifdef PNG_WRITE_SUPPORTED
930
      png_set_write_status_fn(write_ptr, write_row_callback);
931
#endif
932 933
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
934

935 936
   else
   {
937
#ifdef PNG_WRITE_SUPPORTED
938
      png_set_write_status_fn(write_ptr, NULL);
939
#endif
940
      png_set_read_status_fn(read_ptr, NULL);
941 942
   }

943
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
944
   {
945
      int i;
946

947 948
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
949

950
      png_set_read_user_transform_fn(read_ptr, count_filters);
951 952
   }
#endif
953
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
954
   zero_samples = 0;
955 956
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
957

958
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
959 960 961
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
962 963
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
964
#endif
965
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
966 967 968
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
969 970
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
971 972
#endif

973
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
974
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
975

976
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
977 978
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
979

A
Andreas Dilger 已提交
980 981 982 983
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
984
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
985
            color_type, interlace_type, compression_type, filter_type);
986 987 988
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
989 990
      }
   }
991 992
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
993
   {
994
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
995
         blue_y;
996

997 998
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y))
A
Andreas Dilger 已提交
999
      {
1000 1001
         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 已提交
1002
      }
G
Guy Schalnat 已提交
1003
   }
A
Andreas Dilger 已提交
1004
#endif
1005
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
1006
   {
1007
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1008

1009 1010
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1011 1012
   }
#endif
1013
#else /* Use floating point versions */
1014 1015
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1016 1017 1018
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1019

1020 1021 1022 1023 1024 1025 1026 1027
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
1028
#ifdef PNG_gAMA_SUPPORTED
1029 1030 1031 1032 1033 1034 1035
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1036 1037
#endif /* Floating point */
#endif /* Fixed point */
1038
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1039
   {
1040
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1041
      png_bytep profile;
1042
      png_uint_32 proflen;
1043
      int compression_type;
A
Andreas Dilger 已提交
1044

1045 1046
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1047
      {
1048 1049
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1050
      }
G
Guy Schalnat 已提交
1051
   }
1052
#endif
1053
#ifdef PNG_sRGB_SUPPORTED
1054
   {
1055
      int intent;
1056 1057 1058 1059

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1060
#endif
1061 1062 1063 1064 1065 1066 1067
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
1068
#ifdef PNG_bKGD_SUPPORTED
1069 1070 1071 1072 1073 1074 1075 1076 1077
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1078
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1079
   {
A
Andreas Dilger 已提交
1080 1081 1082 1083
      png_uint_16p hist;

      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1084
   }
A
Andreas Dilger 已提交
1085
#endif
1086
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1087
   {
1088
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1089
      int unit_type;
G
Guy Schalnat 已提交
1090

1091
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1092
          &unit_type))
A
Andreas Dilger 已提交
1093 1094 1095 1096 1097
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1098
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
   {
      png_charp purpose, units;
      png_charpp params;
      png_int_32 X0, X1;
      int type, nparams;

      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
         &nparams, &units, &params))
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
1113
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1114 1115 1116 1117 1118 1119 1120 1121
   {
      png_uint_32 res_x, res_y;
      int unit_type;

      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1122
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1123
   {
1124
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1125

1126 1127
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1128
   }
1129
#endif
1130
#ifdef PNG_sCAL_SUPPORTED
1131
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
1132
   {
1133
      int unit;
1134
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1135

1136 1137
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1138
      {
1139
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1140 1141 1142
      }
   }
#else
1143
#ifdef PNG_FIXED_POINT_SUPPORTED
1144
   {
1145
      int unit;
1146
      png_charp scal_width, scal_height;
1147

1148 1149
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1150
      {
1151 1152
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1153 1154
      }
   }
G
Guy Schalnat 已提交
1155
#endif
1156 1157
#endif
#endif
1158
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1159 1160 1161 1162 1163 1164
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1165
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
A
Andreas Dilger 已提交
1166 1167 1168 1169
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1170
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1171 1172 1173 1174 1175 1176
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1177
#ifdef PNG_TIME_RFC1123_SUPPORTED
1178
         /* We have to use png_memcpy instead of "=" because the string
1179 1180 1181
          * pointed to by png_convert_to_rfc1123() gets free'ed before
          * we use it.
          */
1182 1183 1184
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1185

1186
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1187 1188
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1189
      }
A
Andreas Dilger 已提交
1190 1191
   }
#endif
1192
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1193
   {
1194
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1195
      int num_trans;
1196
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1197

1198
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1199
         &trans_color))
A
Andreas Dilger 已提交
1200
      {
1201
         int sample_max = (1 << bit_depth);
1202
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1203
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1204
             (int)trans_color->gray > sample_max) ||
1205
             (color_type == PNG_COLOR_TYPE_RGB &&
1206 1207 1208
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1209
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1210
               trans_color);
A
Andreas Dilger 已提交
1211 1212 1213
      }
   }
#endif
1214
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1215 1216
   {
      png_unknown_chunkp unknowns;
1217
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1218
         &unknowns);
1219

1220 1221
      if (num_unknowns)
      {
1222
         int i;
1223 1224
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1225
         /* Copy the locations from the read_info_ptr.  The automatically
1226 1227 1228
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1229
         for (i = 0; i < num_unknowns; i++)
1230 1231
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1232 1233 1234
      }
   }
#endif
A
Andreas Dilger 已提交
1235

1236
#ifdef PNG_WRITE_SUPPORTED
1237
   pngtest_debug("Writing info struct");
1238 1239

/* If we wanted, we could write info in two steps:
1240
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1241
 */
A
Andreas Dilger 已提交
1242
   png_write_info(write_ptr, write_info_ptr);
1243

1244
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1245 1246
   if (user_chunk_data[0] != 0)
   {
1247
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1248

1249 1250
      unsigned char
        ster_chunk_data[1];
1251

1252 1253 1254
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1255

1256 1257
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1258
   }
1259

1260 1261
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
      png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};

      unsigned char
        vpag_chunk_data[9];

      if (verbose)
         fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n",
           (unsigned long)user_chunk_data[1],
           (unsigned long)user_chunk_data[2],
           (unsigned long)user_chunk_data[3]);
1272

1273 1274 1275 1276
      png_save_uint_32(vpag_chunk_data, user_chunk_data[1]);
      png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]);
      vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff);
      png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
1277 1278 1279
   }

#endif
1280
#endif
A
Andreas Dilger 已提交
1281

1282
#ifdef SINGLE_ROWBUF_ALLOC
1283
   pngtest_debug("Allocating row buffer...");
1284
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1285
      png_get_rowbytes(read_ptr, read_info_ptr));
1286

1287
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1288
#endif /* SINGLE_ROWBUF_ALLOC */
1289
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1290

1291 1292
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1293
   num_pass = png_set_interlace_handling(read_ptr);
1294
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1295
   png_set_interlace_handling(write_ptr);
1296
#  endif
1297
#else
1298
   num_pass = 1;
1299
#endif
A
Andreas Dilger 已提交
1300

1301 1302 1303 1304 1305
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1306 1307
   for (pass = 0; pass < num_pass; pass++)
   {
1308
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1309 1310
      for (y = 0; y < height; y++)
      {
1311
#ifndef SINGLE_ROWBUF_ALLOC
1312
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1313 1314
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1315

1316
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1317
            png_get_rowbytes(read_ptr, read_info_ptr));
1318

1319
#endif /* !SINGLE_ROWBUF_ALLOC */
1320
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1321 1322

#ifdef PNG_WRITE_SUPPORTED
1323 1324 1325 1326 1327
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1328
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1329 1330 1331 1332 1333
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1334 1335 1336
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1337
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1338
         png_free(read_ptr, row_buf);
1339
         row_buf = NULL;
1340
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1341 1342 1343
      }
   }

1344
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1345
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1346
#endif
1347
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1348
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1349 1350
#endif

1351
   pngtest_debug("Reading and writing end_info data");
1352

A
Andreas Dilger 已提交
1353
   png_read_end(read_ptr, end_info_ptr);
1354
#ifdef PNG_TEXT_SUPPORTED
1355 1356 1357 1358 1359 1360
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1361
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1362 1363 1364 1365
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1366
#ifdef PNG_tIME_SUPPORTED
1367 1368 1369 1370 1371 1372
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1373
#ifdef PNG_TIME_RFC1123_SUPPORTED
1374
         /* We have to use png_memcpy instead of "=" because the string
1375 1376
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1377 1378 1379
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1380

1381
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1382 1383 1384 1385
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1386
#endif
1387
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1388 1389
   {
      png_unknown_chunkp unknowns;
1390
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1391
         &unknowns);
1392

1393 1394
      if (num_unknowns)
      {
1395
         int i;
1396 1397
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1398
         /* Copy the locations from the read_info_ptr.  The automatically
1399 1400 1401
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1402
         for (i = 0; i < num_unknowns; i++)
1403 1404
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1405 1406
      }
   }
1407
#endif
1408
#ifdef PNG_WRITE_SUPPORTED
1409
   png_write_end(write_ptr, write_end_info_ptr);
1410
#endif
1411

1412
#ifdef PNG_EASY_ACCESS_SUPPORTED
1413
   if (verbose)
1414 1415 1416 1417
   {
      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);
1418
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1419
         (unsigned long)iwidth, (unsigned long)iheight);
1420 1421
   }
#endif
G
Guy Schalnat 已提交
1422

1423
   pngtest_debug("Destroying data structs");
1424
#ifdef SINGLE_ROWBUF_ALLOC
1425
   pngtest_debug("destroying row_buf for read_ptr");
1426
   png_free(read_ptr, row_buf);
1427
   row_buf = NULL;
1428
#endif /* SINGLE_ROWBUF_ALLOC */
1429
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1430
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1431
#ifdef PNG_WRITE_SUPPORTED
1432
   pngtest_debug("destroying write_end_info_ptr");
1433
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1434
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1435
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1436
#endif
1437
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1438

1439 1440
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1441

1442
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1443
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1444
   {
G
Guy Schalnat 已提交
1445
      fprintf(STDERR, "Could not find file %s\n", inname);
1446
      return (1);
G
Guy Schalnat 已提交
1447 1448
   }

A
Andreas Dilger 已提交
1449
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1450
   {
G
Guy Schalnat 已提交
1451
      fprintf(STDERR, "Could not find file %s\n", outname);
1452
      FCLOSE(fpin);
1453
      return (1);
G
Guy Schalnat 已提交
1454
   }
A
Andreas Dilger 已提交
1455

1456
   for (;;)
G
Guy Schalnat 已提交
1457
   {
A
Andreas Dilger 已提交
1458
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1459

1460 1461
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1462 1463 1464

      if (num_in != num_out)
      {
1465
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1466
                 inname, outname);
1467

1468
         if (wrote_question == 0)
1469 1470
         {
            fprintf(STDERR,
1471
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1472
              inname, PNG_ZBUF_SIZE);
1473
            fprintf(STDERR,
1474
              "\n   filtering heuristic (libpng default), compression");
1475
            fprintf(STDERR,
1476
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1477
              ZLIB_VERSION);
1478
            wrote_question = 1;
1479
         }
1480

1481 1482
         FCLOSE(fpin);
         FCLOSE(fpout);
1483 1484 1485 1486 1487 1488

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

         else
           return (0);
G
Guy Schalnat 已提交
1489 1490 1491 1492 1493
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1494
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1495
      {
1496
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1497

1498
         if (wrote_question == 0)
1499 1500
         {
            fprintf(STDERR,
1501
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1502
                 inname, PNG_ZBUF_SIZE);
1503
            fprintf(STDERR,
1504
              "\n   filtering heuristic (libpng default), compression");
1505
            fprintf(STDERR,
1506
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1507
              ZLIB_VERSION);
1508
            wrote_question = 1;
1509
         }
1510

1511 1512
         FCLOSE(fpin);
         FCLOSE(fpout);
1513 1514 1515 1516 1517 1518

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

         else
           return (0);
G
Guy Schalnat 已提交
1519 1520 1521
      }
   }

1522 1523
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1524

1525
   return (0);
G
Guy Schalnat 已提交
1526
}
G
Guy Schalnat 已提交
1527

1528
/* Input and output filenames */
1529
#ifdef RISCOS
1530 1531
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1532
#else
1533 1534
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1535 1536 1537 1538 1539 1540 1541 1542
#endif

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

1543
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1544
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1545
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1546
   /* Show the version of libpng used in building the library */
1547 1548
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1549
      png_get_header_version(NULL));
1550

1551
   /* Show the version of libpng used in building the application */
1552
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1553
      PNG_HEADER_VERSION_STRING);
1554 1555

   /* Do some consistency checking on the memory allocation settings, I'm
1556 1557 1558 1559
    * 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
    */
1560
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1561
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1562
#endif
1563
   /* I think the following can happen. */
1564
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1565
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1566
#endif
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578

   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)
   {
1579
      if (strcmp(argv[1], "-m") == 0)
1580
      {
1581
         multiple = 1;
1582 1583
         status_dots_requested = 0;
      }
1584

1585 1586 1587 1588 1589
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1590
         status_dots_requested = 1;
1591
      }
1592

1593 1594 1595
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1596
         status_dots_requested = 1;
1597 1598
         inname = argv[2];
      }
1599

1600 1601 1602 1603 1604 1605 1606 1607
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
      }

1608
      else
1609
      {
1610
         inname = argv[1];
1611 1612
         status_dots_requested = 0;
      }
1613 1614
   }

1615 1616
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1617

1618
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1619
   {
1620 1621
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1622
        argv[0], argv[0]);
1623 1624 1625 1626
     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);
1627 1628 1629 1630 1631 1632
     exit(1);
   }

   if (multiple)
   {
      int i;
1633
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1634 1635
      int allocation_now = current_allocation;
#endif
1636
      for (i=2; i<argc; ++i)
1637
      {
1638
         int kerror;
1639
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1640
         kerror = test_one_file(argv[i], outname);
1641
         if (kerror == 0)
1642
         {
1643 1644 1645
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1646
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1647
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1648
               (unsigned long)zero_samples);
1649
#else
1650
            fprintf(STDERR, " PASS\n");
1651
#endif
1652
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1653 1654
            for (k = 0; k<256; k++)
               if (filters_used[k])
1655
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1656
                     k, (unsigned long)filters_used[k]);
1657
#endif
1658
#ifdef PNG_TIME_RFC1123_SUPPORTED
1659 1660
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1661

1662 1663 1664
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1665

1666 1667
         else
         {
1668 1669
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1670
         }
1671
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1672 1673
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1674
               current_allocation - allocation_now);
1675

1676 1677
         if (current_allocation != 0)
         {
1678 1679 1680 1681
            memory_infop pinfo = pinformation;

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

1683 1684
            while (pinfo != NULL)
            {
1685
               fprintf(STDERR, " %lu bytes at %x\n",
1686
                 (unsigned long)pinfo->size,
1687
                 (unsigned int)pinfo->pointer);
1688
               pinfo = pinfo->next;
1689
            }
1690
         }
1691 1692
#endif
      }
1693
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1694
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1695
            current_allocation);
1696
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1697
            maximum_allocation);
1698 1699 1700 1701
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1702
#endif
1703
   }
1704

1705 1706
   else
   {
1707
      int i;
1708
      for (i = 0; i<3; ++i)
1709
      {
1710
         int kerror;
1711
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1712 1713
         int allocation_now = current_allocation;
#endif
1714 1715 1716 1717 1718 1719
         if (i == 1)
            status_dots_requested = 1;

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

1720
         if (i == 0 || verbose == 1 || ierror != 0)
1721
            fprintf(STDERR, "\n Testing %s:", inname);
1722

1723
         kerror = test_one_file(inname, outname);
1724

1725
         if (kerror == 0)
1726
         {
1727
            if (verbose == 1 || i == 2)
1728
            {
1729
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1730
                int k;
1731
#endif
1732
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1733
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1734
                   (unsigned long)zero_samples);
1735 1736 1737
#else
                fprintf(STDERR, " PASS\n");
#endif
1738
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1739 1740
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1741
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1742
                         k, (unsigned long)filters_used[k]);
1743
#endif
1744
#ifdef PNG_TIME_RFC1123_SUPPORTED
1745 1746
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1747 1748
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1749
         }
1750

1751 1752
         else
         {
1753
            if (verbose == 0 && i != 2)
1754
               fprintf(STDERR, "\n Testing %s:", inname);
1755

1756 1757
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1758
         }
1759
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1760 1761
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1762
               current_allocation - allocation_now);
1763

1764 1765
         if (current_allocation != 0)
         {
1766
             memory_infop pinfo = pinformation;
1767

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

1771 1772
             while (pinfo != NULL)
             {
1773 1774
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1775 1776 1777 1778
                pinfo = pinfo->next;
             }
          }
#endif
1779
       }
1780
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1781
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1782
          current_allocation);
1783
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1784
          maximum_allocation);
1785 1786 1787 1788
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1789
#endif
1790 1791
   }

1792 1793 1794 1795
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1796
   fprintf(STDERR, " CPU time used = %.3f seconds",
1797
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1798
   fprintf(STDERR, " (decoding %.3f,\n",
1799
      t_decode/(float)CLOCKS_PER_SEC);
1800
   fprintf(STDERR, "        encoding %.3f ,",
1801
      t_encode/(float)CLOCKS_PER_SEC);
1802
   fprintf(STDERR, " other %.3f seconds)\n\n",
1803 1804 1805
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1806
   if (ierror == 0)
1807
      fprintf(STDERR, " libpng passes test\n");
1808

1809
   else
1810
      fprintf(STDERR, " libpng FAILS test\n");
1811

1812
   return (int)(ierror != 0);
1813
}
1814

1815
/* Generate a compiler error if there is an old png.h in the search path. */
1816
typedef png_libpng_version_1_5_7beta01 Your_png_h_is_not_version_1_5_7beta01;