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

34 35
#define _POSIX_SOURCE 1

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

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

44
#include "png.h"
45

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

#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

J
John Bowler 已提交
105 106 107 108
#ifndef PNG_UNUSED
#  define PNG_UNUSED(param) (void)param;
#endif

109 110 111 112
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

113
#ifndef PNG_FLOATING_POINT_SUPPORTED
114 115 116
#undef PNGTEST_TIMING
#endif

117 118 119 120 121
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

122
#ifdef PNG_TIME_RFC1123_SUPPORTED
123
#define PNG_tIME_STRING_LENGTH 29
124
static int tIME_chunk_present = 0;
125
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
J
John Bowler 已提交
126 127 128 129 130 131 132

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

static int
tIME_to_str(png_structp png_ptr, png_charp ts, png_const_timep t)
{
133
   png_const_charp str = png_convert_to_rfc1123(png_ptr, t);
J
John Bowler 已提交
134

135 136
   if (str == NULL)
       return 0;
J
John Bowler 已提交
137

138 139
   strcpy(ts, str);
   return 1;
J
John Bowler 已提交
140 141
}
#endif /* older libpng */
142 143
#endif

144
static int verbose = 0;
145
static int strict = 0;
146 147 148 149
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 */
150

151 152 153 154 155
/* 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

156 157 158 159 160 161 162 163 164 165 166
/* 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))

167
/* Example of using row callbacks to make a simple progress meter */
168 169 170
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
171

172
static void PNGCBAPI
173
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
174
{
175 176
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
177

178 179 180 181 182 183
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
184

185
   status_dots--;
186

187 188 189 190 191
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
192

193
   fprintf(stdout, "r");
194
}
195

196 197
#ifdef PNG_WRITE_SUPPORTED
static void PNGCBAPI
198
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
199
{
200 201
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
202

203
   fprintf(stdout, "w");
204
}
205
#endif
206 207


208
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
J
John Bowler 已提交
209
/* Example of using a user transform callback (doesn't do anything at present).
210
 */
211
static void PNGCBAPI
J
John Bowler 已提交
212
read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data)
213
{
J
John Bowler 已提交
214 215 216
   PNG_UNUSED(png_ptr)
   PNG_UNUSED(row_info)
   PNG_UNUSED(data)
217 218 219
}
#endif

220
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
221
/* Example of using user transform callback (we don't transform anything,
222 223
 * but merely count the zero samples)
 */
224

225
static png_uint_32 zero_samples;
226

227
static void PNGCBAPI
228
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
229 230
{
   png_bytep dp = data;
231 232
   if (png_ptr == NULL)
      return;
233

234
   /* Contents of row_info:
235 236 237 238 239 240 241 242
    *  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)
    */

243
   /* Counts the number of zero samples (or zero pixels if color_type is 3 */
244

245 246 247 248
   if (row_info->color_type == 0 || row_info->color_type == 3)
   {
      int pos = 0;
      png_uint_32 n, nstop;
249

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

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

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

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

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

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

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

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

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

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

               dp+=2;
            }
         }
         if (row_info->color_type > 3)
         {
            dp++;
            if (row_info->bit_depth == 16)
               dp++;
         }
      }
   }
332
}
333
#endif /* WRITE_USER_TRANSFORM */
334

335
#ifndef PNG_STDIO_SUPPORTED
336
/* START of code to validate stdio-free compilation */
337 338 339 340 341 342 343
/* 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.
 */
344

345 346 347
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
348
    png_uint_32 io_op);
349 350
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
351
    png_uint_32 io_op)
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
{
   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 */
   }
382
   if (err != 0)
383 384 385 386
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

387
static void PNGCBAPI
388
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
389
{
390 391
   png_size_t check = 0;
   png_voidp io_ptr;
392 393 394 395

   /* 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.
    */
396 397 398
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
399
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
400
   }
401

402 403
   if (check != length)
   {
404
      png_error(png_ptr, "Read Error");
405
   }
406 407 408 409

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

412
#ifdef PNG_WRITE_FLUSH_SUPPORTED
413
static void PNGCBAPI
414
pngtest_flush(png_structp png_ptr)
415
{
416
   /* Do nothing; fflush() is said to be just a waste of energy. */
417
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
418 419
}
#endif
G
Guy Schalnat 已提交
420

421
/* This is the function that does the actual writing of data.  If you are
422 423 424 425
 * 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.
 */
426
static void PNGCBAPI
427
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
428
{
429
   png_size_t check;
430

431
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
432

433 434 435 436
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
437 438 439 440

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
441
}
442
#endif /* !STDIO */
443 444 445 446 447 448

/* 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.
 */
449 450 451 452 453
typedef struct
{
   PNG_CONST char *file_name;
}  pngtest_error_parameters;

454
static void PNGCBAPI
455
pngtest_warning(png_structp png_ptr, png_const_charp message)
456 457
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
458 459
   pngtest_error_parameters *test =
      (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
460

461
   ++warning_count;
462

463 464 465 466
   if (test != NULL && test->file_name != NULL)
      name = test->file_name;

   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
467 468 469 470 471 472 473
}

/* 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().
 */
474
static void PNGCBAPI
475
pngtest_error(png_structp png_ptr, png_const_charp message)
476
{
477 478
   ++error_count;

479
   pngtest_warning(png_ptr, message);
480
   /* We can return because png_error calls the default handler, which is
481 482
    * actually OK in this case.
    */
483
}
484

485 486
/* END of code to validate stdio-free compilation */

487
/* START of code to validate memory allocation and deallocation */
488
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
489 490

/* Allocate memory.  For reasonable files, size should never exceed
491
 * 64K.  However, zlib may allocate more than 64K if you don't tell
492 493 494 495 496 497 498
 * 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.
 */
499 500
typedef struct memory_information
{
501
   png_alloc_size_t          size;
502
   png_voidp                 pointer;
503
   struct memory_information *next;
504
} memory_information;
505
typedef memory_information *memory_infop;
506 507

static memory_infop pinformation = NULL;
508 509 510 511
static int current_allocation = 0;
static int maximum_allocation = 0;
static int total_allocation = 0;
static int num_allocations = 0;
512

513 514 515
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));
516 517

png_voidp
518
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
519
{
520

521
   /* png_malloc has already tested for NULL; png_create_struct calls
522 523
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
524

525
   if (size == 0)
526
      return (NULL);
527 528 529 530

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
531
      /* Disable malloc_fn and free_fn */
532
      memory_infop pinfo;
533
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
534
      pinfo = (memory_infop)png_malloc(png_ptr,
535
          (sizeof *pinfo));
536 537
      pinfo->size = size;
      current_allocation += size;
538 539
      total_allocation += size;
      num_allocations ++;
540

541 542
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
543

544
      pinfo->pointer = png_malloc(png_ptr, size);
545
      /* Restore malloc_fn and free_fn */
546

547 548
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
549

550 551 552 553
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
554
         png_error(png_ptr,
555
           "out of memory in pngtest->png_debug_malloc");
556
      }
557

558 559 560
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
561
      memset(pinfo->pointer, 0xdd, pinfo->size);
562

563
      if (verbose != 0)
564
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
565
             pinfo->pointer);
566

567
      return (png_voidp)(pinfo->pointer);
568 569 570 571
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
572
void PNGCBAPI
573
png_debug_free(png_structp png_ptr, png_voidp ptr)
574 575
{
   if (png_ptr == NULL)
576
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
577

578 579
   if (ptr == 0)
   {
580 581 582 583 584 585 586
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
587
   if (pinformation != NULL)
588
   {
589
      memory_infop *ppinfo = &pinformation;
590

591 592
      for (;;)
      {
593
         memory_infop pinfo = *ppinfo;
594

595 596
         if (pinfo->pointer == ptr)
         {
597
            *ppinfo = pinfo->next;
598 599
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
600 601
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
602
               the memory that is to be freed. */
603
            memset(ptr, 0x55, pinfo->size);
604
            free(pinfo);
605
            pinfo = NULL;
606 607
            break;
         }
608

609 610
         if (pinfo->next == NULL)
         {
611
            fprintf(STDERR, "Pointer %p not found\n", ptr);
612 613
            break;
         }
614

615 616 617 618 619
         ppinfo = &pinfo->next;
      }
   }

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

623
   if (ptr != NULL)
624
      free(ptr);
625
   ptr = NULL;
626
}
627
#endif /* USER_MEM && DEBUG */
628 629
/* END of code to test memory allocation/deallocation */

630

631
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
632 633
/* Demonstration of user chunk support of the sTER and vpAg chunks */

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

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
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
653

654 655 656 657 658 659 660 661 662 663 664 665
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;

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

669
   /* Find where we are (the code below zeroes info_ptr to indicate that the
670 671 672 673 674
    * chunks before the first IDAT have been read.)
    */
   if (data->info_ptr == NULL) /* after IDAT */
      location = what | after_IDAT;

675
   else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0)
676 677 678 679 680 681 682 683 684 685 686 687 688
      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 */
}
689

690
static int PNGCBAPI
691
read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
692
{
693 694 695 696 697
   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");
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717

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

719 720
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
721

722
         if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
723 724 725 726 727 728 729
         {
            my_user_chunk_data->sTER_mode=chunk->data[0];
            return (1);
         }

         else
            return (0); /* duplicate sTER - give it to libpng */
730 731 732 733 734 735 736 737 738 739 740
      }

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

741
   if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
742
      return (0);  /* duplicate vpAg */
743

744 745 746
   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];
747 748

   return (1);
749 750 751 752 753 754
}

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

757
   if (verbose != 0)
758
      fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode);
759

760
   png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1);
761
}
762 763 764 765

static void
write_vpAg_chunk(png_structp write_ptr)
{
766
   png_byte vpAg[5] = {118, 112,  65, 103, '\0'};
767 768 769

   png_byte vpag_chunk_data[9];

770
   if (verbose != 0)
771
      fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
772 773 774
          (unsigned long)user_chunk_data.vpAg_width,
          (unsigned long)user_chunk_data.vpAg_height,
          user_chunk_data.vpAg_units);
775 776 777 778

   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;
779
   png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
}

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);
   }
}
802 803
#endif /* WRITE */
#else /* !READ_USER_CHUNKS */
804
#  define write_chunks(pp,loc) ((void)0)
805 806 807
#endif
/* END of code to demonstrate user chunk support */

808 809 810 811 812 813
/* START of code to check that libpng has the required text support; this only
 * checks for the write support because if read support is missing the chunk
 * will simply not be reported back to pngtest.
 */
#ifdef PNG_TEXT_SUPPORTED
static void
J
John Bowler 已提交
814
pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr,
815
    int num_text)
816 817 818 819 820 821 822 823 824 825 826
{
   while (num_text > 0)
   {
      switch (text_ptr[--num_text].compression)
      {
         case PNG_TEXT_COMPRESSION_NONE:
            break;

         case PNG_TEXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_zTXt_SUPPORTED
               ++unsupported_chunks;
J
John Bowler 已提交
827 828
               /* In libpng 1.7 this now does an app-error, so stop it: */
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
829 830 831 832 833 834 835
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
J
John Bowler 已提交
836
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
837 838 839 840 841 842 843 844 845 846 847 848 849
#           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 */

850
/* Test one file */
851
static int
852
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
853
{
854 855
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
856
   pngtest_error_parameters error_parameters;
857 858 859 860 861 862
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
J
John Bowler 已提交
863
#ifdef PNG_WRITE_FILTER_SUPPORTED
864
   int interlace_preserved = 1;
J
John Bowler 已提交
865 866
#endif /* WRITE_FILTER */
#else /* !WRITE */
867 868 869
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
J
John Bowler 已提交
870
#endif /* !WRITE */
G
Guy Schalnat 已提交
871
   png_bytep row_buf;
G
Guy Schalnat 已提交
872
   png_uint_32 y;
A
Andreas Dilger 已提交
873
   png_uint_32 width, height;
J
John Bowler 已提交
874 875
   volatile int num_passes;
   int pass;
A
Andreas Dilger 已提交
876
   int bit_depth, color_type;
877

878
   row_buf = NULL;
879
   error_parameters.file_name = inname;
G
Guy Schalnat 已提交
880

A
Andreas Dilger 已提交
881
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
882 883
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
884
      return (1);
G
Guy Schalnat 已提交
885 886
   }

A
Andreas Dilger 已提交
887
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
888
   {
G
Guy Schalnat 已提交
889
      fprintf(STDERR, "Could not open output file %s\n", outname);
890
      FCLOSE(fpin);
891
      return (1);
G
Guy Schalnat 已提交
892 893
   }

894
   pngtest_debug("Allocating read and write structures");
895
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
896
   read_ptr =
897 898
       png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
       NULL, NULL, NULL, png_debug_malloc, png_debug_free);
899
#else
900
   read_ptr =
901
       png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
902
#endif
903
   png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
904
       pngtest_warning);
905

906
#ifdef PNG_WRITE_SUPPORTED
907
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
908
   write_ptr =
909 910
       png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
       NULL, NULL, NULL, png_debug_malloc, png_debug_free);
911
#else
912
   write_ptr =
913
       png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
914
#endif
915
   png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
916
       pngtest_warning);
917
#endif
918
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
919
   read_info_ptr = png_create_info_struct(read_ptr);
920
   end_info_ptr = png_create_info_struct(read_ptr);
921 922
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
923
   write_end_info_ptr = png_create_info_struct(write_ptr);
924
#endif
G
Guy Schalnat 已提交
925

926 927 928
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
   init_callback_info(read_info_ptr);
   png_set_read_user_chunk_fn(read_ptr, &user_chunk_data,
929
       read_user_chunk_callback);
930 931
#endif

932
#ifdef PNG_SETJMP_SUPPORTED
933
   pngtest_debug("Setting jmpbuf for read struct");
934
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
935
   {
936
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
937 938
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
939
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
940
#ifdef PNG_WRITE_SUPPORTED
941
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
942
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
943
#endif
944 945
      FCLOSE(fpin);
      FCLOSE(fpout);
946
      return (1);
G
Guy Schalnat 已提交
947
   }
A
Andreas Dilger 已提交
948

949
#ifdef PNG_WRITE_SUPPORTED
950
   pngtest_debug("Setting jmpbuf for write struct");
951

952
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
953
   {
954
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
955
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
956
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
957
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
958
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
959
#endif
960 961
      FCLOSE(fpin);
      FCLOSE(fpout);
962
      return (1);
G
Guy Schalnat 已提交
963
   }
964
#endif
A
Andreas Dilger 已提交
965
#endif
966

967
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
968
   if (strict != 0)
969 970 971 972
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);

973
# ifdef PNG_WRITE_SUPPORTED
974 975
      /* Treat them as errors on write */
      png_set_benign_errors(write_ptr, 0);
976
# endif
977 978 979 980 981 982 983

      /* 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'.
       */
   }

984
   else if (relaxed != 0)
985 986 987 988
   {
      /* Allow application (pngtest) errors and warnings to pass */
      png_set_benign_errors(read_ptr, 1);

989
      /* Turn off CRC checking while reading */
990 991
      png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);

992
#ifdef PNG_IGNORE_ADLER32
993 994 995 996
      /* Turn off ADLER32 checking while reading */
      png_set_option(read_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
#endif

997
# ifdef PNG_WRITE_SUPPORTED
998
      png_set_benign_errors(write_ptr, 1);
999
# endif
1000

1001
   }
1002
#endif /* BENIGN_ERRORS */
1003

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1137
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1138
          &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1139 1140
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
1141
             red_y, green_x, green_y, blue_x, blue_y);
1142 1143 1144
      }
   }
#endif
1145
#ifdef PNG_gAMA_SUPPORTED
1146 1147 1148
   {
      double gamma;

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

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

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

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

1189
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1190 1191 1192 1193 1194
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1195 1196 1197
#ifdef PNG_eXIf_SUPPORTED
   {
      png_bytep exif;
1198
      png_uint_32 exif_length;
1199

1200
      if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0)
1201 1202 1203
      {
         printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1],
            (int)exif_length);
1204
         png_set_eXIf_1(write_ptr, write_info_ptr, exif_length, exif);
1205
      }
1206 1207
   }
#endif
1208
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1209
   {
A
Andreas Dilger 已提交
1210 1211
      png_uint_16p hist;

1212
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1213
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1214
   }
A
Andreas Dilger 已提交
1215
#endif
1216
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1217
   {
1218
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1219
      int unit_type;
G
Guy Schalnat 已提交
1220

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

1248 1249
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1250 1251 1252
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1253
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1254
   {
1255
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1256

1257
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1258
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1259
   }
1260
#endif
1261
#ifdef PNG_sCAL_SUPPORTED
1262 1263
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1264
   {
1265
      int unit;
1266
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1267

1268
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1269
          &scal_height) != 0)
G
Guy Schalnat 已提交
1270
      {
1271
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1272 1273 1274
      }
   }
#else
1275
#ifdef PNG_FIXED_POINT_SUPPORTED
1276
   {
1277
      int unit;
1278
      png_charp scal_width, scal_height;
1279

1280
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1281
           &scal_height) != 0)
1282
      {
1283 1284
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1285 1286
      }
   }
J
John Bowler 已提交
1287 1288 1289
#endif
#endif
#endif
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300

#ifdef PNG_sPLT_SUPPORTED
   {
       png_sPLT_tp entries;

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

1303
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1304 1305 1306 1307 1308 1309
   {
      png_textp text_ptr;
      int num_text;

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

1312 1313
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1314
         if (verbose != 0)
1315 1316 1317 1318 1319 1320 1321
         {
            int i;

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

A
Andreas Dilger 已提交
1326 1327 1328
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
J
John Bowler 已提交
1329
#endif
1330
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1331 1332 1333
   {
      png_timep mod_time;

1334
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1335 1336
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1337
#ifdef PNG_TIME_RFC1123_SUPPORTED
1338
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1339
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1340 1341

         else
1342 1343 1344 1345
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1346

1347
         tIME_chunk_present++;
1348
#endif /* TIME_RFC1123 */
1349
      }
A
Andreas Dilger 已提交
1350
   }
J
John Bowler 已提交
1351
#endif
1352
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1353
   {
1354
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1355
      int num_trans;
1356
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1357

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

1380
      if (num_unknowns != 0)
1381 1382
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1383
             num_unknowns);
1384
#if PNG_LIBPNG_VER < 10600
1385
         /* Copy the locations from the read_info_ptr.  The automatically
1386 1387
          * 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).
1388
          */
1389 1390 1391 1392
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1393
                  unknowns[i].location);
1394 1395
         }
#endif
1396 1397 1398
      }
   }
#endif
A
Andreas Dilger 已提交
1399

1400
#ifdef PNG_WRITE_SUPPORTED
1401
   pngtest_debug("Writing info struct");
1402

1403 1404 1405 1406
   /* 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);
1407

1408
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1409

1410
   png_write_info(write_ptr, write_info_ptr);
1411

1412
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1413

1414 1415 1416 1417
   png_write_info(write_ptr, write_end_info_ptr);

   write_chunks(write_ptr, after_IDAT); /* after IDAT */

1418 1419 1420 1421
#ifdef PNG_COMPRESSION_COMPAT
   /* Test the 'compatibility' setting here, if it is available. */
   png_set_compression(write_ptr, PNG_COMPRESSION_COMPAT);
#endif
1422
#endif
A
Andreas Dilger 已提交
1423

1424
#ifdef SINGLE_ROWBUF_ALLOC
1425
   pngtest_debug("Allocating row buffer...");
1426
   row_buf = (png_bytep)png_malloc(read_ptr,
1427
       png_get_rowbytes(read_ptr, read_info_ptr));
1428

1429
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1430
#endif /* SINGLE_ROWBUF_ALLOC */
1431
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1432

J
John Bowler 已提交
1433 1434 1435 1436 1437 1438 1439 1440
#if defined(PNG_READ_INTERLACING_SUPPORTED) &&\
   defined(PNG_WRITE_INTERLACING_SUPPORTED)
   /* Both must be defined for libpng to be able to handle the interlace,
    * otherwise it gets handled below by simply reading and writing the passes
    * directly.
    */
   if (png_set_interlace_handling(read_ptr) != num_passes)
      png_error(write_ptr,
1441
          "png_set_interlace_handling(read): wrong pass count ");
J
John Bowler 已提交
1442 1443
   if (png_set_interlace_handling(write_ptr) != num_passes)
      png_error(write_ptr,
1444
          "png_set_interlace_handling(write): wrong pass count ");
J
John Bowler 已提交
1445 1446 1447
#else /* png_set_interlace_handling not called on either read or write */
#  define calc_pass_height
#endif /* not using libpng interlace handling */
A
Andreas Dilger 已提交
1448

1449 1450 1451 1452 1453
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
J
John Bowler 已提交
1454
   for (pass = 0; pass < num_passes; pass++)
A
Andreas Dilger 已提交
1455
   {
J
John Bowler 已提交
1456 1457
#     ifdef calc_pass_height
         png_uint_32 pass_height;
1458

J
John Bowler 已提交
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
         if (num_passes == 7) /* interlaced */
         {
            if (PNG_PASS_COLS(width, pass) > 0)
               pass_height = PNG_PASS_ROWS(height, pass);

            else
               pass_height = 0;
         }

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

1474
      pngtest_debug1("Writing row data for pass %d", pass);
J
John Bowler 已提交
1475
      for (y = 0; y < pass_height; y++)
A
Andreas Dilger 已提交
1476
      {
1477
#ifndef SINGLE_ROWBUF_ALLOC
1478
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1479

1480
         row_buf = (png_bytep)png_malloc(read_ptr,
1481
             png_get_rowbytes(read_ptr, read_info_ptr));
1482

1483
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
1484
             (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1485

1486
#endif /* !SINGLE_ROWBUF_ALLOC */
1487
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1488 1489

#ifdef PNG_WRITE_SUPPORTED
1490 1491 1492 1493 1494
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1495
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1496 1497 1498 1499 1500
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1501
#endif /* WRITE */
1502 1503

#ifndef SINGLE_ROWBUF_ALLOC
1504
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1505
         png_free(read_ptr, row_buf);
1506
         row_buf = NULL;
1507
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1508 1509 1510
      }
   }

1511 1512 1513 1514 1515 1516 1517
#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
1518 1519
#endif

1520
   pngtest_debug("Reading and writing end_info data");
1521

A
Andreas Dilger 已提交
1522
   png_read_end(read_ptr, end_info_ptr);
1523
#ifdef PNG_TEXT_SUPPORTED
1524 1525 1526 1527 1528 1529
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1530
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1531 1532 1533

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1534
         if (verbose != 0)
1535 1536 1537 1538 1539 1540 1541
         {
            int i;

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

1546 1547 1548 1549
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1550 1551 1552
#ifdef PNG_eXIf_SUPPORTED
   {
      png_bytep exif;
1553
      png_uint_32 exif_length;
1554

1555
      if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0)
1556 1557 1558
      {
         printf(" eXIf type %c%c, %d bytes\n",exif[0],exif[1],
            (int)exif_length);
1559
         png_set_eXIf_1(write_ptr, write_end_info_ptr, exif_length, exif);
1560
      }
1561 1562
   }
#endif
1563
#ifdef PNG_tIME_SUPPORTED
1564 1565 1566
   {
      png_timep mod_time;

1567
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1568 1569
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1570
#ifdef PNG_TIME_RFC1123_SUPPORTED
1571
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1572
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1573 1574

         else
1575 1576 1577 1578
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1579

1580
         tIME_chunk_present++;
1581
#endif /* TIME_RFC1123 */
1582 1583
      }
   }
1584
#endif
1585
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1586 1587
   {
      png_unknown_chunkp unknowns;
1588
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1589
          &unknowns);
1590

1591
      if (num_unknowns != 0)
1592 1593
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1594
             num_unknowns);
1595
#if PNG_LIBPNG_VER < 10600
1596
         /* Copy the locations from the read_info_ptr.  The automatically
1597 1598
          * 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).
1599
          */
1600 1601 1602 1603
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1604
                  unknowns[i].location);
1605 1606
         }
#endif
1607 1608
      }
   }
1609
#endif
1610

1611
#ifdef PNG_WRITE_SUPPORTED
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
#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);

1628
   png_write_end(write_ptr, write_end_info_ptr);
1629
#endif
1630

1631
#ifdef PNG_EASY_ACCESS_SUPPORTED
1632
   if (verbose != 0)
1633 1634 1635 1636
   {
      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);
1637
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1638
          (unsigned long)iwidth, (unsigned long)iheight);
1639 1640
   }
#endif
G
Guy Schalnat 已提交
1641

1642
   pngtest_debug("Destroying data structs");
1643
#ifdef SINGLE_ROWBUF_ALLOC
1644
   pngtest_debug("destroying row_buf for read_ptr");
1645
   png_free(read_ptr, row_buf);
1646
   row_buf = NULL;
1647
#endif /* SINGLE_ROWBUF_ALLOC */
1648
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1649
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1650
#ifdef PNG_WRITE_SUPPORTED
1651
   pngtest_debug("destroying write_end_info_ptr");
1652
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1653
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1654
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1655
#endif
1656
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1657

1658 1659
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1660

1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
   /* 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)",
1671
          inname, error_count, warning_count);
1672 1673 1674 1675 1676 1677

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

#  ifdef PNG_WRITE_SUPPORTED
J
John Bowler 已提交
1678
      /* If there is no write support nothing was written! */
1679 1680 1681
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
1682
             inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
1683 1684 1685 1686 1687 1688
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
1689
          inname, warning_count);
1690 1691 1692 1693 1694

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

1695
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1696
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1697
   {
G
Guy Schalnat 已提交
1698
      fprintf(STDERR, "Could not find file %s\n", inname);
1699
      return (1);
G
Guy Schalnat 已提交
1700 1701
   }

A
Andreas Dilger 已提交
1702
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1703
   {
G
Guy Schalnat 已提交
1704
      fprintf(STDERR, "Could not find file %s\n", outname);
1705
      FCLOSE(fpin);
1706
      return (1);
G
Guy Schalnat 已提交
1707
   }
A
Andreas Dilger 已提交
1708

J
John Bowler 已提交
1709 1710
#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
    defined (PNG_WRITE_FILTER_SUPPORTED)
1711
   if (interlace_preserved != 0) /* else the files will be changed */
G
Guy Schalnat 已提交
1712
   {
1713
      for (;;)
1714
      {
1715
         static int wrote_question = 0;
1716 1717 1718
         png_size_t num_in, num_out;
         char inbuf[256], outbuf[256];

1719 1720
         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1721

1722
         if (num_in != num_out)
1723
         {
1724
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1725
                inname, outname);
1726

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

1741 1742
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1743

1744 1745
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1746

1747 1748 1749
            else
              return (0);
         }
1750

1751
         if (num_in == 0)
1752
            break;
1753

1754
         if (memcmp(inbuf, outbuf, num_in))
1755
         {
1756
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
1757
                outname);
1758 1759 1760 1761

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1762 1763
                   "   Was %s written with the same maximum"
                   " IDAT chunk size (%d bytes),",
1764 1765
                    inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
1766
                   "\n   filtering heuristic (libpng default), compression");
1767
               fprintf(STDERR,
1768
                   " level (zlib default),\n   and zlib version (%s)?\n\n",
1769 1770 1771
                 ZLIB_VERSION);
               wrote_question = 1;
            }
1772

1773 1774
            FCLOSE(fpin);
            FCLOSE(fpout);
1775

1776 1777 1778 1779 1780 1781 1782
            /* 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);
1783

1784 1785 1786
            else
              return (0);
         }
G
Guy Schalnat 已提交
1787 1788
      }
   }
J
John Bowler 已提交
1789
#endif /* WRITE && WRITE_FILTER */
G
Guy Schalnat 已提交
1790

1791 1792
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1793

1794
   return (0);
G
Guy Schalnat 已提交
1795
}
G
Guy Schalnat 已提交
1796

1797
/* Input and output filenames */
1798
#ifdef RISCOS
1799 1800
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1801
#else
1802 1803
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1804 1805 1806 1807 1808 1809 1810 1811
#endif

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

1812 1813
   png_structp dummy_ptr;

1814
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1815
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1816
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1817
   /* Show the version of libpng used in building the library */
1818
   fprintf(STDERR, " library (%lu):%s",
1819 1820
       (unsigned long)png_access_version_number(),
       png_get_header_version(NULL));
1821

1822
   /* Show the version of libpng used in building the application */
1823
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1824
       PNG_HEADER_VERSION_STRING);
1825 1826

   /* Do some consistency checking on the memory allocation settings, I'm
1827 1828 1829 1830
    * 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
    */
1831
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1832
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1833
#endif
1834
   /* I think the following can happen. */
1835
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1836
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1837
#endif
1838 1839 1840 1841

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
1842
          "Warning: versions are different between png.h and png.c\n");
1843 1844 1845 1846 1847 1848 1849
      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)
   {
1850
      if (strcmp(argv[1], "-m") == 0)
1851
      {
1852
         multiple = 1;
1853 1854
         status_dots_requested = 0;
      }
1855

1856 1857 1858 1859 1860
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1861
         status_dots_requested = 1;
1862
      }
1863

1864 1865 1866
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1867
         status_dots_requested = 1;
1868 1869
         inname = argv[2];
      }
1870

1871 1872 1873 1874 1875 1876
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
         relaxed = 0;
      }

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

1889
      else
1890
      {
1891
         inname = argv[1];
1892 1893
         status_dots_requested = 0;
      }
1894 1895
   }

1896
   if (multiple == 0 && argc == 3 + verbose)
1897
      outname = argv[2 + verbose];
1898

1899 1900
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
1901
   {
1902 1903 1904 1905 1906 1907 1908 1909
      fprintf(STDERR,
          "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
          argv[0], argv[0]);
      fprintf(STDERR,
          "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
      fprintf(STDERR,
          "  with -m %s is used as a temporary file\n", outname);
      exit(1);
1910 1911
   }

1912
   if (multiple != 0)
1913 1914
   {
      int i;
1915
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1916
      int allocation_now = current_allocation;
1917
#endif
1918
      for (i=2; i<argc; ++i)
1919
      {
1920
         int kerror;
1921
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1922 1923 1924
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
1925
         kerror = test_one_file(argv[i], outname);
1926
         if (kerror == 0)
1927
         {
1928
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1929
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1930
                (unsigned long)zero_samples);
1931
#else
1932
            fprintf(STDERR, " PASS\n");
1933
#endif
1934
#ifdef PNG_TIME_RFC1123_SUPPORTED
1935 1936
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
1937

1938
            tIME_chunk_present = 0;
1939
#endif /* TIME_RFC1123 */
1940
         }
1941

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

1952 1953
         if (current_allocation != 0)
         {
1954 1955
            memory_infop pinfo = pinformation;

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

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

1981 1982
   else
   {
1983
      int i;
1984
      for (i = 0; i<3; ++i)
1985
      {
1986
         int kerror;
1987
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1988
         int allocation_now = current_allocation;
1989
#endif
1990 1991 1992 1993 1994 1995
         if (i == 1)
            status_dots_requested = 1;

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

1996
         if (i == 0 || verbose == 1 || ierror != 0)
1997
         {
1998
            fprintf(STDERR, "\n Testing %s:", inname);
1999 2000 2001 2002
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
2003

2004
         kerror = test_one_file(inname, outname);
2005

2006
         if (kerror == 0)
2007
         {
2008
            if (verbose == 1 || i == 2)
2009
            {
2010
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
2011
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
2012
                    (unsigned long)zero_samples);
2013 2014 2015
#else
                fprintf(STDERR, " PASS\n");
#endif
2016
#ifdef PNG_TIME_RFC1123_SUPPORTED
2017 2018
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
2019
#endif /* TIME_RFC1123 */
2020
            }
2021
         }
2022

2023 2024
         else
         {
2025
            if (verbose == 0 && i != 2)
2026
            {
2027
               fprintf(STDERR, "\n Testing %s:", inname);
2028 2029 2030 2031
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
2032

2033 2034
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
2035
         }
2036
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2037
         if (allocation_now != current_allocation)
2038 2039
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
                 current_allocation - allocation_now);
2040

2041 2042
         if (current_allocation != 0)
         {
2043
             memory_infop pinfo = pinformation;
2044

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

2048 2049
             while (pinfo != NULL)
             {
2050
                fprintf(STDERR, " %lu bytes at %p\n",
2051
                    (unsigned long)pinfo->size, pinfo->pointer);
2052 2053 2054 2055
                pinfo = pinfo->next;
             }
          }
#endif
2056
       }
2057
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2058 2059 2060 2061 2062 2063 2064 2065
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
           current_allocation);
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
           maximum_allocation);
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
           total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
           num_allocations);
2066
#endif
2067 2068
   }

2069 2070 2071 2072
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
2073
   fprintf(STDERR, " CPU time used = %.3f seconds",
2074
       (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
2075
   fprintf(STDERR, " (decoding %.3f,\n",
2076
       t_decode/(float)CLOCKS_PER_SEC);
2077
   fprintf(STDERR, "        encoding %.3f ,",
2078
       t_encode/(float)CLOCKS_PER_SEC);
2079
   fprintf(STDERR, " other %.3f seconds)\n\n",
2080
       t_misc/(float)CLOCKS_PER_SEC);
2081 2082
#endif

2083
   if (ierror == 0)
2084
      fprintf(STDERR, " libpng passes test\n");
2085

2086
   else
2087
      fprintf(STDERR, " libpng FAILS test\n");
2088

2089 2090 2091
   dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   fprintf(STDERR, " Default limits:\n");
   fprintf(STDERR, "  width_max  = %lu\n",
2092
       (unsigned long) png_get_user_width_max(dummy_ptr));
2093
   fprintf(STDERR, "  height_max = %lu\n",
2094
       (unsigned long) png_get_user_height_max(dummy_ptr));
2095 2096 2097 2098
   if (png_get_chunk_cache_max(dummy_ptr) == 0)
      fprintf(STDERR, "  cache_max  = unlimited\n");
   else
      fprintf(STDERR, "  cache_max  = %lu\n",
2099
          (unsigned long) png_get_chunk_cache_max(dummy_ptr));
2100 2101 2102 2103
   if (png_get_chunk_malloc_max(dummy_ptr) == 0)
      fprintf(STDERR, "  malloc_max = unlimited\n");
   else
      fprintf(STDERR, "  malloc_max = %lu\n",
2104
          (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
2105 2106
   png_destroy_read_struct(&dummy_ptr, NULL, NULL);

2107
   return (int)(ierror != 0);
2108
}
2109 2110 2111 2112 2113
#else
int
main(void)
{
   fprintf(STDERR,
2114
       " test ignored because libpng was not built with read support\n");
2115
   /* And skip this test */
2116
   return PNG_LIBPNG_VER < 10600 ? 0 : 77;
2117 2118
}
#endif
2119

2120
/* Generate a compiler error if there is an old png.h in the search path. */
2121
typedef png_libpng_version_1_6_32beta01 Your_png_h_is_not_version_1_6_32beta01;