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

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * Copyright (c) 2018 Cosmin Truta
C
Cosmin Truta 已提交
5
 * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
6 7
 * Copyright (c) 1996-1997 Andreas Dilger
 * 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
static int relaxed = 0;
147
static int xfail = 0;
148 149 150
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 */
151

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

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

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

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

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

186
   status_dots--;
187

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

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

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

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


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

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

226
static png_uint_32 zero_samples;
227

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

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

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

246 247 248 249
   if (row_info->color_type == 0 || row_info->color_type == 3)
   {
      int pos = 0;
      png_uint_32 n, nstop;
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 332
      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++;
         }
      }
   }
333
}
334
#endif /* WRITE_USER_TRANSFORM */
335

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

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

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

394
   /* fread() returns 0 on error, so it is OK to store this in a size_t
395 396
    * instead of an int, which is what fread() actually returns.
    */
397 398 399
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
400
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
401
   }
402

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

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

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

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

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

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

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

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

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

462
   ++warning_count;
463

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

631

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

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

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

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

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

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

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

691
static int PNGCBAPI
692
read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
693
{
694 695 696 697 698
   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");
699 700 701 702 703 704 705 706 707

   /* 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;
708
    * size_t size;
709 710 711 712 713 714 715 716 717 718
    *
    * 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 */
719

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

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

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

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

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

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

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

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

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

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

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

   png_byte vpag_chunk_data[9];

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

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

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

809 810 811 812 813 814
/* 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 已提交
815
pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr,
816
    int num_text)
817 818 819 820 821 822 823 824 825 826 827
{
   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 已提交
828 829
               /* In libpng 1.7 this now does an app-error, so stop it: */
               text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
830 831 832 833 834 835 836
#           endif
            break;

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

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

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

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

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

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

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

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

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

954
#ifdef PNG_WRITE_SUPPORTED
955
   pngtest_debug("Setting jmpbuf for write struct");
956

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

974
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
975
   if (strict != 0)
976 977 978 979
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);

980
# ifdef PNG_WRITE_SUPPORTED
981 982
      /* Treat them as errors on write */
      png_set_benign_errors(write_ptr, 0);
983
# endif
984 985 986 987 988 989 990

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

991
   else if (relaxed != 0)
992 993 994 995
   {
      /* Allow application (pngtest) errors and warnings to pass */
      png_set_benign_errors(read_ptr, 1);

996
      /* Turn off CRC checking while reading */
997 998
      png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);

999
#ifdef PNG_IGNORE_ADLER32
1000 1001 1002 1003
      /* Turn off ADLER32 checking while reading */
      png_set_option(read_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
#endif

1004
# ifdef PNG_WRITE_SUPPORTED
1005
      png_set_benign_errors(write_ptr, 1);
1006
# endif
1007

1008
   }
1009
#endif /* BENIGN_ERRORS */
1010

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1196
      if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1197 1198 1199 1200 1201
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1202
#ifdef PNG_READ_eXIf_SUPPORTED
1203
   {
1204
      png_bytep exif=NULL;
1205
      png_uint_32 exif_length;
1206

1207
      if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0)
1208
      {
1209
         if (exif_length > 1)
1210
            fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1],
1211
               (unsigned long)exif_length);
1212
# ifdef PNG_WRITE_eXIf_SUPPORTED
1213
         png_set_eXIf_1(write_ptr, write_info_ptr, exif_length, exif);
1214
# endif
1215
      }
1216 1217
   }
#endif
1218
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1219
   {
A
Andreas Dilger 已提交
1220 1221
      png_uint_16p hist;

1222
      if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
A
Andreas Dilger 已提交
1223
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
1224
   }
A
Andreas Dilger 已提交
1225
#endif
1226
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1227
   {
1228
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1229
      int unit_type;
G
Guy Schalnat 已提交
1230

1231
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1232
          &unit_type) != 0)
A
Andreas Dilger 已提交
1233 1234 1235 1236 1237
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1238
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1239 1240 1241 1242 1243 1244 1245
   {
      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,
1246
          &nparams, &units, &params) != 0)
A
Andreas Dilger 已提交
1247 1248
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
1249
             nparams, units, params);
A
Andreas Dilger 已提交
1250 1251 1252
      }
   }
#endif
1253
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1254 1255 1256 1257
   {
      png_uint_32 res_x, res_y;
      int unit_type;

1258 1259
      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
          &unit_type) != 0)
A
Andreas Dilger 已提交
1260 1261 1262
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
1263
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1264
   {
1265
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1266

1267
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1268
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1269
   }
1270
#endif
1271
#ifdef PNG_sCAL_SUPPORTED
1272 1273
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
   defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
G
Guy Schalnat 已提交
1274
   {
1275
      int unit;
1276
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1277

1278
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1279
          &scal_height) != 0)
G
Guy Schalnat 已提交
1280
      {
1281
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1282 1283 1284
      }
   }
#else
1285
#ifdef PNG_FIXED_POINT_SUPPORTED
1286
   {
1287
      int unit;
1288
      png_charp scal_width, scal_height;
1289

1290
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1291
           &scal_height) != 0)
1292
      {
1293 1294
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1295 1296
      }
   }
J
John Bowler 已提交
1297 1298 1299
#endif
#endif
#endif
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310

#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 已提交
1311
#endif
1312

1313
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1314 1315 1316 1317 1318 1319
   {
      png_textp text_ptr;
      int num_text;

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

1322 1323
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1324
         if (verbose != 0)
1325 1326 1327
         {
            int i;

1328
            fprintf(STDERR,"\n");
1329 1330
            for (i=0; i<num_text; i++)
            {
1331
               fprintf(STDERR,"   Text compression[%d]=%d\n",
1332
                   i, text_ptr[i].compression);
1333 1334
            }
         }
1335

A
Andreas Dilger 已提交
1336 1337 1338
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
J
John Bowler 已提交
1339
#endif
1340
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1341 1342 1343
   {
      png_timep mod_time;

1344
      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
A
Andreas Dilger 已提交
1345 1346
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1347
#ifdef PNG_TIME_RFC1123_SUPPORTED
1348
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1349
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1350 1351

         else
1352 1353 1354 1355
         {
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
         }
1356

1357
         tIME_chunk_present++;
1358
#endif /* TIME_RFC1123 */
1359
      }
A
Andreas Dilger 已提交
1360
   }
J
John Bowler 已提交
1361
#endif
1362
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1363
   {
1364
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1365
      int num_trans;
1366
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1367

1368
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1369
          &trans_color) != 0)
A
Andreas Dilger 已提交
1370
      {
1371
         int sample_max = (1 << bit_depth);
1372
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1373
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1374
             (int)trans_color->gray > sample_max) ||
1375
             (color_type == PNG_COLOR_TYPE_RGB &&
1376 1377 1378
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1379
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1380
               trans_color);
A
Andreas Dilger 已提交
1381 1382
      }
   }
J
John Bowler 已提交
1383
#endif
1384
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1385 1386
   {
      png_unknown_chunkp unknowns;
1387
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1388
          &unknowns);
1389

1390
      if (num_unknowns != 0)
1391 1392
      {
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1393
             num_unknowns);
1394
#if PNG_LIBPNG_VER < 10600
1395
         /* Copy the locations from the read_info_ptr.  The automatically
1396 1397
          * 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).
1398
          */
1399 1400 1401 1402
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1403
                  unknowns[i].location);
1404 1405
         }
#endif
1406 1407 1408
      }
   }
#endif
A
Andreas Dilger 已提交
1409

1410
#ifdef PNG_WRITE_SUPPORTED
1411
   pngtest_debug("Writing info struct");
1412

1413 1414 1415 1416
   /* 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);
1417

1418
   write_chunks(write_ptr, before_PLTE); /* before PLTE */
1419

1420
   png_write_info(write_ptr, write_info_ptr);
1421

1422
   write_chunks(write_ptr, before_IDAT); /* after PLTE */
1423

1424 1425 1426 1427
   png_write_info(write_ptr, write_end_info_ptr);

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

1428 1429 1430 1431
#ifdef PNG_COMPRESSION_COMPAT
   /* Test the 'compatibility' setting here, if it is available. */
   png_set_compression(write_ptr, PNG_COMPRESSION_COMPAT);
#endif
1432
#endif
A
Andreas Dilger 已提交
1433

1434
#ifdef SINGLE_ROWBUF_ALLOC
1435
   pngtest_debug("Allocating row buffer...");
1436
   row_buf = (png_bytep)png_malloc(read_ptr,
1437
       png_get_rowbytes(read_ptr, read_info_ptr));
1438

1439
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1440
#endif /* SINGLE_ROWBUF_ALLOC */
1441
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1442

J
John Bowler 已提交
1443 1444 1445 1446 1447 1448 1449 1450
#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,
1451
          "png_set_interlace_handling(read): wrong pass count ");
J
John Bowler 已提交
1452 1453
   if (png_set_interlace_handling(write_ptr) != num_passes)
      png_error(write_ptr,
1454
          "png_set_interlace_handling(write): wrong pass count ");
J
John Bowler 已提交
1455 1456 1457
#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 已提交
1458

1459 1460 1461 1462 1463
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
J
John Bowler 已提交
1464
   for (pass = 0; pass < num_passes; pass++)
A
Andreas Dilger 已提交
1465
   {
J
John Bowler 已提交
1466 1467
#     ifdef calc_pass_height
         png_uint_32 pass_height;
1468

J
John Bowler 已提交
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
         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

1484
      pngtest_debug1("Writing row data for pass %d", pass);
J
John Bowler 已提交
1485
      for (y = 0; y < pass_height; y++)
A
Andreas Dilger 已提交
1486
      {
1487
#ifndef SINGLE_ROWBUF_ALLOC
1488
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1489

1490
         row_buf = (png_bytep)png_malloc(read_ptr,
1491
             png_get_rowbytes(read_ptr, read_info_ptr));
1492

1493
         pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
1494
             (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1495

1496
#endif /* !SINGLE_ROWBUF_ALLOC */
1497
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1498 1499

#ifdef PNG_WRITE_SUPPORTED
1500 1501 1502 1503 1504
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1505
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1506 1507 1508 1509 1510
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1511
#endif /* WRITE */
1512 1513

#ifndef SINGLE_ROWBUF_ALLOC
1514
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1515
         png_free(read_ptr, row_buf);
1516
         row_buf = NULL;
1517
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1518 1519 1520
      }
   }

1521 1522 1523 1524 1525 1526 1527
#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
1528 1529
#endif

1530
   pngtest_debug("Reading and writing end_info data");
1531

A
Andreas Dilger 已提交
1532
   png_read_end(read_ptr, end_info_ptr);
1533
#ifdef PNG_TEXT_SUPPORTED
1534 1535 1536 1537 1538 1539
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1540
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1541 1542 1543

         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1544
         if (verbose != 0)
1545 1546 1547
         {
            int i;

1548
            fprintf(STDERR,"\n");
1549 1550
            for (i=0; i<num_text; i++)
            {
1551
               fprintf(STDERR,"   Text compression[%d]=%d\n",
1552
                   i, text_ptr[i].compression);
1553 1554 1555
            }
         }

1556 1557 1558 1559
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1560
#ifdef PNG_READ_eXIf_SUPPORTED
1561
   {
1562
      png_bytep exif=NULL;
1563
      png_uint_32 exif_length;
1564

1565
      if (png_get_eXIf_1(read_ptr, end_info_ptr, &exif_length, &exif) != 0)
1566
      {
1567
         if (exif_length > 1)
1568
            fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1],
1569
               (unsigned long)exif_length);
1570
# ifdef PNG_WRITE_eXIf_SUPPORTED
1571
         png_set_eXIf_1(write_ptr, write_end_info_ptr, exif_length, exif);
1572
# endif
1573
      }
1574 1575
   }
#endif
1576
#ifdef PNG_tIME_SUPPORTED
1577 1578 1579
   {
      png_timep mod_time;

1580
      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1581 1582
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1583
#ifdef PNG_TIME_RFC1123_SUPPORTED
1584
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1585
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1586 1587

         else
1588 1589 1590 1591
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1592

1593
         tIME_chunk_present++;
1594
#endif /* TIME_RFC1123 */
1595 1596
      }
   }
1597
#endif
1598
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1599 1600
   {
      png_unknown_chunkp unknowns;
1601
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1602
          &unknowns);
1603

1604
      if (num_unknowns != 0)
1605 1606
      {
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1607
             num_unknowns);
1608
#if PNG_LIBPNG_VER < 10600
1609
         /* Copy the locations from the read_info_ptr.  The automatically
1610 1611
          * 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).
1612
          */
1613 1614 1615 1616
         {
            int i;
            for (i = 0; i < num_unknowns; i++)
              png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1617
                  unknowns[i].location);
1618 1619
         }
#endif
1620 1621
      }
   }
1622
#endif
1623

1624
#ifdef PNG_WRITE_SUPPORTED
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
#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);

1641
   png_write_end(write_ptr, write_end_info_ptr);
1642
#endif
1643

1644
#ifdef PNG_EASY_ACCESS_SUPPORTED
1645
   if (verbose != 0)
1646 1647 1648 1649
   {
      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);
1650
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1651
          (unsigned long)iwidth, (unsigned long)iheight);
1652 1653
   }
#endif
G
Guy Schalnat 已提交
1654

1655
   pngtest_debug("Destroying data structs");
1656
#ifdef SINGLE_ROWBUF_ALLOC
1657
   pngtest_debug("destroying row_buf for read_ptr");
1658
   png_free(read_ptr, row_buf);
1659
   row_buf = NULL;
1660
#endif /* SINGLE_ROWBUF_ALLOC */
1661
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1662
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1663
#ifdef PNG_WRITE_SUPPORTED
1664
   pngtest_debug("destroying write_end_info_ptr");
1665
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1666
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1667
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1668
#endif
1669
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1670

1671 1672
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1673

1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
   /* 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)",
1684
          inname, error_count, warning_count);
1685 1686 1687 1688 1689 1690

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

#  ifdef PNG_WRITE_SUPPORTED
J
John Bowler 已提交
1691
      /* If there is no write support nothing was written! */
1692 1693 1694
      else if (unsupported_chunks > 0)
      {
         fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
1695
             inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
1696 1697 1698 1699 1700 1701
      }
#  endif

   else if (warning_count > 0)
   {
      fprintf(STDERR, "\n  %s: %d libpng warnings found",
1702
          inname, warning_count);
1703 1704 1705 1706 1707

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

1708
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1709
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1710
   {
G
Guy Schalnat 已提交
1711
      fprintf(STDERR, "Could not find file %s\n", inname);
1712
      return (1);
G
Guy Schalnat 已提交
1713 1714
   }

A
Andreas Dilger 已提交
1715
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1716
   {
G
Guy Schalnat 已提交
1717
      fprintf(STDERR, "Could not find file %s\n", outname);
1718
      FCLOSE(fpin);
1719
      return (1);
G
Guy Schalnat 已提交
1720
   }
A
Andreas Dilger 已提交
1721

J
John Bowler 已提交
1722 1723
#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\
    defined (PNG_WRITE_FILTER_SUPPORTED)
1724
   if (interlace_preserved != 0) /* else the files will be changed */
G
Guy Schalnat 已提交
1725
   {
1726
      for (;;)
1727
      {
1728
         static int wrote_question = 0;
1729
         size_t num_in, num_out;
1730 1731
         char inbuf[256], outbuf[256];

1732 1733
         num_in = fread(inbuf, 1, sizeof inbuf, fpin);
         num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1734

1735
         if (num_in != num_out)
1736
         {
1737
            fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1738
                inname, outname);
1739

1740 1741 1742
            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1743 1744 1745
                   "   Was %s written with the same maximum IDAT"
                   " chunk size (%d bytes),",
                   inname, PNG_ZBUF_SIZE);
1746
               fprintf(STDERR,
1747
                   "\n   filtering heuristic (libpng default), compression");
1748
               fprintf(STDERR,
1749 1750
                   " level (zlib default),\n   and zlib version (%s)?\n\n",
                   ZLIB_VERSION);
1751 1752
               wrote_question = 1;
            }
1753

1754 1755
            FCLOSE(fpin);
            FCLOSE(fpout);
G
Guy Schalnat 已提交
1756

1757 1758
            if (strict != 0 && unsupported_chunks == 0)
              return (1);
G
Guy Schalnat 已提交
1759

1760 1761 1762
            else
              return (0);
         }
1763

1764
         if (num_in == 0)
1765
            break;
1766

1767
         if (memcmp(inbuf, outbuf, num_in))
1768
         {
1769
            fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
1770
                outname);
1771 1772 1773 1774

            if (wrote_question == 0 && unsupported_chunks == 0)
            {
               fprintf(STDERR,
1775 1776
                   "   Was %s written with the same maximum"
                   " IDAT chunk size (%d bytes),",
1777 1778
                    inname, PNG_ZBUF_SIZE);
               fprintf(STDERR,
1779
                   "\n   filtering heuristic (libpng default), compression");
1780
               fprintf(STDERR,
1781
                   " level (zlib default),\n   and zlib version (%s)?\n\n",
1782 1783 1784
                 ZLIB_VERSION);
               wrote_question = 1;
            }
1785

1786 1787
            FCLOSE(fpin);
            FCLOSE(fpout);
1788

1789 1790 1791 1792 1793 1794 1795
            /* 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);
1796

1797 1798 1799
            else
              return (0);
         }
G
Guy Schalnat 已提交
1800 1801
      }
   }
J
John Bowler 已提交
1802
#endif /* WRITE && WRITE_FILTER */
G
Guy Schalnat 已提交
1803

1804 1805
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1806

1807
   return (0);
G
Guy Schalnat 已提交
1808
}
G
Guy Schalnat 已提交
1809

1810
/* Input and output filenames */
1811
#ifdef RISCOS
1812 1813
static const char *inname = "pngtest/png";
static const char *outname = "pngout/png";
1814
#else
1815 1816
static const char *inname = "pngtest.png";
static const char *outname = "pngout.png";
1817 1818 1819 1820 1821 1822 1823 1824
#endif

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

1825 1826
   png_structp dummy_ptr;

1827
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1828
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1829
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1830
   /* Show the version of libpng used in building the library */
1831
   fprintf(STDERR, " library (%lu):%s",
1832 1833
       (unsigned long)png_access_version_number(),
       png_get_header_version(NULL));
1834

1835
   /* Show the version of libpng used in building the application */
1836
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1837
       PNG_HEADER_VERSION_STRING);
1838 1839

   /* Do some consistency checking on the memory allocation settings, I'm
1840 1841 1842 1843
    * 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
    */
1844
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1845
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1846
#endif
1847
   /* I think the following can happen. */
1848
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1849
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1850
#endif
1851 1852 1853 1854

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
1855
          "Warning: versions are different between png.h and png.c\n");
1856 1857 1858 1859 1860 1861 1862
      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)
   {
1863
      if (strcmp(argv[1], "-m") == 0)
1864
      {
1865
         multiple = 1;
1866 1867
         status_dots_requested = 0;
      }
1868

1869 1870 1871 1872 1873
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1874
         status_dots_requested = 1;
1875
      }
1876

1877 1878 1879
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1880
         status_dots_requested = 1;
1881 1882
         inname = argv[2];
      }
1883

1884 1885 1886 1887 1888 1889
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
1890
         relaxed = 0;
1891
         multiple=1;
1892 1893 1894 1895 1896 1897 1898 1899 1900
      }

      else if (strcmp(argv[1], "--relaxed") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict = 0;
         relaxed++;
1901
         multiple=1;
1902
      }
1903 1904 1905 1906 1907 1908 1909 1910
      else if (strcmp(argv[1], "--xfail") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict = 0;
         xfail++;
         relaxed++;
1911
         multiple=1;
1912
      }
1913

1914
      else
1915
      {
1916
         inname = argv[1];
1917 1918
         status_dots_requested = 0;
      }
1919 1920
   }

1921
   if (multiple == 0 && argc == 3 + verbose)
1922
      outname = argv[2 + verbose];
1923

1924 1925
   if ((multiple == 0 && argc > 3 + verbose) ||
       (multiple != 0 && argc < 2))
1926
   {
1927 1928 1929 1930 1931 1932 1933 1934
      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);
1935 1936
   }

1937
   if (multiple != 0)
1938 1939
   {
      int i;
1940
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1941
      int allocation_now = current_allocation;
1942
#endif
1943
      for (i=2; i<argc; ++i)
1944
      {
1945
         int kerror;
1946
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1947 1948 1949
#if PNG_DEBUG > 0
         fprintf(STDERR, "\n");
#endif
1950
         kerror = test_one_file(argv[i], outname);
1951
         if (kerror == 0)
1952
         {
1953
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1954
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1955
                (unsigned long)zero_samples);
1956
#else
1957
            fprintf(STDERR, " PASS\n");
1958
#endif
1959
#ifdef PNG_TIME_RFC1123_SUPPORTED
1960 1961
            if (tIME_chunk_present != 0)
               fprintf(STDERR, " tIME = %s\n", tIME_string);
1962

1963
            tIME_chunk_present = 0;
1964
#endif /* TIME_RFC1123 */
1965
         }
1966

1967 1968
         else
         {
1969 1970 1971 1972 1973 1974 1975
            if (xfail)
              fprintf(STDERR, " XFAIL\n");
            else
            {
              fprintf(STDERR, " FAIL\n");
              ierror += kerror;
            }
1976
         }
1977
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1978
         if (allocation_now != current_allocation)
1979 1980
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
                current_allocation - allocation_now);
1981

1982 1983
         if (current_allocation != 0)
         {
1984 1985
            memory_infop pinfo = pinformation;

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

1989 1990
            while (pinfo != NULL)
            {
1991
               fprintf(STDERR, " %lu bytes at %p\n",
1992 1993
                   (unsigned long)pinfo->size,
                   pinfo->pointer);
1994
               pinfo = pinfo->next;
1995
            }
1996
         }
1997 1998
#endif
      }
1999
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2000 2001 2002 2003 2004 2005 2006 2007
         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);
2008
#endif
2009
   }
2010

2011 2012
   else
   {
2013
      int i;
2014
      for (i = 0; i<3; ++i)
2015
      {
2016
         int kerror;
2017
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2018
         int allocation_now = current_allocation;
2019
#endif
2020 2021 2022 2023 2024 2025
         if (i == 1)
            status_dots_requested = 1;

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

2026
         if (i == 0 || verbose == 1 || ierror != 0)
2027
         {
2028
            fprintf(STDERR, "\n Testing %s:", inname);
2029 2030 2031 2032
#if PNG_DEBUG > 0
            fprintf(STDERR, "\n");
#endif
         }
2033

2034
         kerror = test_one_file(inname, outname);
2035

2036
         if (kerror == 0)
2037
         {
2038
            if (verbose == 1 || i == 2)
2039
            {
2040
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
2041
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
2042
                    (unsigned long)zero_samples);
2043 2044 2045
#else
                fprintf(STDERR, " PASS\n");
#endif
2046
#ifdef PNG_TIME_RFC1123_SUPPORTED
2047 2048
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
2049
#endif /* TIME_RFC1123 */
2050
            }
2051
         }
2052

2053 2054
         else
         {
2055
            if (verbose == 0 && i != 2)
2056
            {
2057
               fprintf(STDERR, "\n Testing %s:", inname);
2058 2059 2060 2061
#if PNG_DEBUG > 0
               fprintf(STDERR, "\n");
#endif
            }
2062

2063 2064 2065 2066 2067 2068 2069
            if (xfail)
              fprintf(STDERR, " XFAIL\n");
            else
            {
              fprintf(STDERR, " FAIL\n");
              ierror += kerror;
            }
2070
         }
2071
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2072
         if (allocation_now != current_allocation)
2073 2074
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
                 current_allocation - allocation_now);
2075

2076 2077
         if (current_allocation != 0)
         {
2078
             memory_infop pinfo = pinformation;
2079

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

2083 2084
             while (pinfo != NULL)
             {
2085
                fprintf(STDERR, " %lu bytes at %p\n",
2086
                    (unsigned long)pinfo->size, pinfo->pointer);
2087 2088 2089 2090
                pinfo = pinfo->next;
             }
          }
#endif
2091
       }
2092
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
2093 2094 2095 2096 2097 2098 2099 2100
       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);
2101
#endif
2102 2103
   }

2104 2105 2106 2107
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
2108
   fprintf(STDERR, " CPU time used = %.3f seconds",
2109
       (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
2110
   fprintf(STDERR, " (decoding %.3f,\n",
2111
       t_decode/(float)CLOCKS_PER_SEC);
2112
   fprintf(STDERR, "        encoding %.3f ,",
2113
       t_encode/(float)CLOCKS_PER_SEC);
2114
   fprintf(STDERR, " other %.3f seconds)\n\n",
2115
       t_misc/(float)CLOCKS_PER_SEC);
2116 2117
#endif

2118
   if (ierror == 0)
2119
      fprintf(STDERR, " libpng passes test\n");
2120

2121
   else
2122
      fprintf(STDERR, " libpng FAILS test\n");
2123

2124 2125 2126
   dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   fprintf(STDERR, " Default limits:\n");
   fprintf(STDERR, "  width_max  = %lu\n",
2127
       (unsigned long) png_get_user_width_max(dummy_ptr));
2128
   fprintf(STDERR, "  height_max = %lu\n",
2129
       (unsigned long) png_get_user_height_max(dummy_ptr));
2130 2131 2132 2133
   if (png_get_chunk_cache_max(dummy_ptr) == 0)
      fprintf(STDERR, "  cache_max  = unlimited\n");
   else
      fprintf(STDERR, "  cache_max  = %lu\n",
2134
          (unsigned long) png_get_chunk_cache_max(dummy_ptr));
2135 2136 2137 2138
   if (png_get_chunk_malloc_max(dummy_ptr) == 0)
      fprintf(STDERR, "  malloc_max = unlimited\n");
   else
      fprintf(STDERR, "  malloc_max = %lu\n",
2139
          (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
2140 2141
   png_destroy_read_struct(&dummy_ptr, NULL, NULL);

2142
   return (int)(ierror != 0);
2143
}
2144 2145 2146 2147 2148
#else
int
main(void)
{
   fprintf(STDERR,
2149
       " test ignored because libpng was not built with read support\n");
2150
   /* And skip this test */
2151
   return PNG_LIBPNG_VER < 10600 ? 0 : 77;
2152 2153
}
#endif
2154

2155
/* Generate a compiler error if there is an old png.h in the search path. */
C
Cosmin Truta 已提交
2156
typedef png_libpng_version_1_6_36 Your_png_h_is_not_version_1_6_36;