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

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

34 35
#define _POSIX_SOURCE 1

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

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

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

56 57 58 59 60 61 62 63 64
#if PNG_DEBUG > 1
#  define pngtest_debug(m)        ((void)fprintf(stderr, m "\n"))
#  define pngtest_debug1(m,p1)    ((void)fprintf(stderr, m "\n", p1))
#  define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2))
#else
#  define pngtest_debug(m)        ((void)0)
#  define pngtest_debug1(m,p1)    ((void)0)
#  define pngtest_debug2(m,p1,p2) ((void)0)
#endif
65

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

70 71 72 73
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

74
#ifndef PNG_FLOATING_POINT_SUPPORTED
75 76 77
#undef PNGTEST_TIMING
#endif

78 79 80 81 82
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

83
#ifdef PNG_TIME_RFC1123_SUPPORTED
84
#define PNG_tIME_STRING_LENGTH 29
85
static int tIME_chunk_present = 0;
86
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
87 88
#endif

89
static int verbose = 0;
90
static int strict = 0;
91

G
Guy Schalnat 已提交
92 93 94 95
#ifdef __TURBOC__
#include <mem.h>
#endif

96
/* Defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
97
/*  #define STDERR stderr  */
98
#define STDERR stdout   /* For DOS */
G
Guy Schalnat 已提交
99

100 101 102 103 104
/* 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

105
/* Example of using row callbacks to make a simple progress meter */
106 107 108
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
109

110
static void PNGCBAPI
111
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
112
{
113 114
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
115

116 117 118 119 120 121
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
122

123
   status_dots--;
124

125 126 127 128 129
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
130

131
   fprintf(stdout, "r");
132
}
133

134
static void PNGCBAPI
135
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
136
{
137 138
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
139

140
   fprintf(stdout, "w");
141 142 143
}


144
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
145
/* Example of using user transform callback (we don't transform anything,
146 147 148
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
149
static png_uint_32 filters_used[256];
150
static void PNGCBAPI
151 152
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
153
   if (png_ptr != NULL && row_info != NULL)
154
      ++filters_used[*(data - 1)];
155 156 157
}
#endif

158
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
159
/* Example of using user transform callback (we don't transform anything,
160 161
 * but merely count the zero samples)
 */
162

163
static png_uint_32 zero_samples;
164

165
static void PNGCBAPI
166
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
167 168
{
   png_bytep dp = data;
169 170
   if (png_ptr == NULL)
      return;
171

172
   /* Contents of row_info:
173 174 175 176 177 178 179 180
    *  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)
    */

181
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
182

183
    if (row_info->color_type == 0 || row_info->color_type == 3)
184
    {
185
       int pos = 0;
186
       png_uint_32 n, nstop;
187

188
       for (n = 0, nstop=row_info->width; n<nstop; n++)
189
       {
190
          if (row_info->bit_depth == 1)
191
          {
192 193
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
194

195
             if (pos == 8)
196
             {
197
                pos = 0;
198 199
                dp++;
             }
200
          }
201

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

207
             if (pos == 8)
208
             {
209
                pos = 0;
210 211
                dp++;
             }
212
          }
213

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

219
             if (pos == 8)
220
             {
221
                pos = 0;
222 223
                dp++;
             }
224
          }
225

226
          if (row_info->bit_depth == 8)
227 228
             if (*dp++ == 0)
                zero_samples++;
229

230
          if (row_info->bit_depth == 16)
231
          {
232 233
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
234 235 236 237
             dp+=2;
          }
       }
    }
238
    else /* Other color types */
239
    {
240
       png_uint_32 n, nstop;
241 242
       int channel;
       int color_channels = row_info->channels;
243
       if (row_info->color_type > 3)color_channels--;
244

245
       for (n = 0, nstop=row_info->width; n<nstop; n++)
246 247 248
       {
          for (channel = 0; channel < color_channels; channel++)
          {
249
             if (row_info->bit_depth == 8)
250 251
                if (*dp++ == 0)
                   zero_samples++;
252

253
             if (row_info->bit_depth == 16)
254
             {
255 256
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
257

258 259 260
                dp+=2;
             }
          }
261
          if (row_info->color_type > 3)
262 263
          {
             dp++;
264 265
             if (row_info->bit_depth == 16)
                dp++;
266 267 268 269
          }
       }
    }
}
270
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
271

272
static int wrote_question = 0;
273

274
#ifndef PNG_STDIO_SUPPORTED
275
/* START of code to validate stdio-free compilation */
276 277 278 279 280 281 282
/* 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.
 */
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
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op)
{
   png_uint_32 io_state = png_get_io_state(png_ptr);
   int err = 0;

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

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

326
static void PNGCBAPI
327
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
328
{
329 330
   png_size_t check = 0;
   png_voidp io_ptr;
331 332 333 334

   /* 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.
    */
335 336 337 338 339
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
340

341 342
   if (check != length)
   {
343
      png_error(png_ptr, "Read Error");
344
   }
345 346 347 348

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

351
#ifdef PNG_WRITE_FLUSH_SUPPORTED
352
static void PNGCBAPI
353
pngtest_flush(png_structp png_ptr)
354
{
355
   /* Do nothing; fflush() is said to be just a waste of energy. */
356
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
357 358
}
#endif
G
Guy Schalnat 已提交
359

360
/* This is the function that does the actual writing of data.  If you are
361 362 363 364
 * 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.
 */
365
static void PNGCBAPI
366
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
367
{
368
   png_size_t check;
369

370
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
371

372 373 374 375
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
376 377 378 379

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
380 381 382 383 384 385 386
}

/* 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.
 */
387
static void PNGCBAPI
388
pngtest_warning(png_structp png_ptr, png_const_charp message)
389 390
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
391 392
   char *test;
   test = png_get_error_ptr(png_ptr);
393

394 395
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
396

397 398
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
399 400 401 402 403 404 405
}

/* 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().
 */
406
static void PNGCBAPI
407
pngtest_error(png_structp png_ptr, png_const_charp message)
408
{
409
   pngtest_warning(png_ptr, message);
410
   /* We can return because png_error calls the default handler, which is
411 412
    * actually OK in this case.
    */
413
}
414
#endif /* !PNG_STDIO_SUPPORTED */
415 416
/* END of code to validate stdio-free compilation */

417
/* START of code to validate memory allocation and deallocation */
418
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
419 420

/* Allocate memory.  For reasonable files, size should never exceed
421 422 423 424 425 426 427 428
 * 64K.  However, zlib may allocate more then 64K if you don't tell
 * it not to.  See zconf.h and png.h for more information.  zlib does
 * need to allocate exactly 64K, so whatever you call here must
 * have the ability to do that.
 *
 * This piece of code can be compiled to validate max 64K allocations
 * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
 */
429 430
typedef struct memory_information
{
431
   png_alloc_size_t          size;
432
   png_voidp                 pointer;
433
   struct memory_information *next;
434
} memory_information;
435
typedef memory_information *memory_infop;
436 437 438 439

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
440 441
static int total_allocation = 0;
static int num_allocations = 0;
442

443 444 445
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));
446 447

png_voidp
448
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
449
{
450

451
   /* png_malloc has already tested for NULL; png_create_struct calls
452 453
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
454

455
   if (size == 0)
456
      return (NULL);
457 458 459 460

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
461
      /* Disable malloc_fn and free_fn */
462
      memory_infop pinfo;
463
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
464 465
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
466 467
      pinfo->size = size;
      current_allocation += size;
468 469
      total_allocation += size;
      num_allocations ++;
470

471 472
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
473

474
      pinfo->pointer = png_malloc(png_ptr, size);
475
      /* Restore malloc_fn and free_fn */
476

477 478
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
479

480 481 482 483
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
484
         png_error(png_ptr,
485
           "out of memory in pngtest->png_debug_malloc");
486
      }
487

488 489 490
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
491
      memset(pinfo->pointer, 0xdd, pinfo->size);
492

493
      if (verbose)
494
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
495
            pinfo->pointer);
496

497
      return (png_voidp)(pinfo->pointer);
498 499 500 501
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
502
void PNGCBAPI
503
png_debug_free(png_structp png_ptr, png_voidp ptr)
504 505
{
   if (png_ptr == NULL)
506
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
507

508 509
   if (ptr == 0)
   {
510 511 512 513 514 515 516 517
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
518
      memory_infop *ppinfo = &pinformation;
519

520 521
      for (;;)
      {
522
         memory_infop pinfo = *ppinfo;
523

524 525
         if (pinfo->pointer == ptr)
         {
526 527 528 529 530
            *ppinfo = pinfo->next;
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
531
               the memory that is to be freed. */
532
            memset(ptr, 0x55, pinfo->size);
533
            png_free_default(png_ptr, pinfo);
534
            pinfo = NULL;
535 536
            break;
         }
537

538 539
         if (pinfo->next == NULL)
         {
540
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
541 542
            break;
         }
543

544 545 546 547 548
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
549
   if (verbose)
550
      printf("Freeing %p\n", ptr);
551

552
   png_free_default(png_ptr, ptr);
553
   ptr = NULL;
554
}
555
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
556 557
/* END of code to test memory allocation/deallocation */

558 559

/* Demonstration of user chunk support of the sTER and vpAg chunks */
560
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
561

562
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
563 564 565 566
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

567 568 569 570
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
571 572
     */

573
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
574 575
   png_unknown_chunkp chunk)
{
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
   png_uint_32
     *my_user_chunk_data;

   /* Return one of the following:
    *    return (-n);  chunk had an error
    *    return (0);  did not recognize
    *    return (n);  success
    *
    * The unknown chunk structure contains the chunk data:
    * png_byte name[5];
    * png_byte *data;
    * png_size_t size;
    *
    * Note that libpng has already taken care of the CRC handling.
    */

   if (chunk->name[0] == 115 && chunk->name[1] ==  84 &&     /* s  T */
       chunk->name[2] ==  69 && chunk->name[3] ==  82)       /* E  R */
      {
         /* Found sTER chunk */
         if (chunk->size != 1)
            return (-1); /* Error return */
598

599 600
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
601

602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
         my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
         my_user_chunk_data[0]=chunk->data[0]+1;
         return (1);
      }

   if (chunk->name[0] != 118 || chunk->name[1] != 112 ||    /* v  p */
       chunk->name[2] !=  65 || chunk->name[3] != 103)      /* A  g */
      return (0); /* Did not recognize */

   /* Found ImageMagick vpAg chunk */

   if (chunk->size != 9)
      return (-1); /* Error return */

   my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);

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

   return (1);
623 624 625 626 627

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

628
/* Test one file */
629
static int
630
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
631
{
632 633
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
634 635 636 637 638 639 640 641 642 643 644
   png_structp read_ptr;
   png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED
   png_structp write_ptr;
   png_infop write_info_ptr;
   png_infop write_end_info_ptr;
#else
   png_structp write_ptr = NULL;
   png_infop write_info_ptr = NULL;
   png_infop write_end_info_ptr = NULL;
#endif
G
Guy Schalnat 已提交
645
   png_bytep row_buf;
G
Guy Schalnat 已提交
646
   png_uint_32 y;
A
Andreas Dilger 已提交
647 648 649
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
650

651
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
652

653
   row_buf = NULL;
G
Guy Schalnat 已提交
654

A
Andreas Dilger 已提交
655
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
656 657
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
658
      return (1);
G
Guy Schalnat 已提交
659 660
   }

A
Andreas Dilger 已提交
661
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
662
   {
G
Guy Schalnat 已提交
663
      fprintf(STDERR, "Could not open output file %s\n", outname);
664
      FCLOSE(fpin);
665
      return (1);
G
Guy Schalnat 已提交
666 667
   }

668
   pngtest_debug("Allocating read and write structures");
669
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
670 671
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
672
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
673
#else
674 675
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
676
#endif
677
#ifndef PNG_STDIO_SUPPORTED
678 679
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
680
#endif
681

682
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
683 684 685 686 687 688
   user_chunk_data[0] = 0;
   user_chunk_data[1] = 0;
   user_chunk_data[2] = 0;
   user_chunk_data[3] = 0;
   png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
     read_user_chunk_callback);
689

690
#endif
691
#ifdef PNG_WRITE_SUPPORTED
692
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
693 694 695
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
696
#else
697 698
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
699
#endif
700
#ifndef PNG_STDIO_SUPPORTED
701 702
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
703
#endif
704
#endif
705
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
706
   read_info_ptr = png_create_info_struct(read_ptr);
707
   end_info_ptr = png_create_info_struct(read_ptr);
708 709
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
710
   write_end_info_ptr = png_create_info_struct(write_ptr);
711
#endif
G
Guy Schalnat 已提交
712

713
#ifdef PNG_SETJMP_SUPPORTED
714
   pngtest_debug("Setting jmpbuf for read struct");
715
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
716
   {
717
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
718 719
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
720
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
721
#ifdef PNG_WRITE_SUPPORTED
722
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
723
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
724
#endif
725 726
      FCLOSE(fpin);
      FCLOSE(fpout);
727
      return (1);
G
Guy Schalnat 已提交
728
   }
A
Andreas Dilger 已提交
729

730
#ifdef PNG_WRITE_SUPPORTED
731
   pngtest_debug("Setting jmpbuf for write struct");
732

733
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
734
   {
735
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
736
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
737
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
738
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
739
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
740
#endif
741 742
      FCLOSE(fpin);
      FCLOSE(fpout);
743
      return (1);
G
Guy Schalnat 已提交
744
   }
745
#endif
A
Andreas Dilger 已提交
746
#endif
747

748 749 750 751 752 753 754 755 756 757 758
   if (strict)
   {
      /* Treat png_benign_error() as errors on read */
      png_set_benign_errors(read_ptr, 0);
   
      /* Treat them as errors on write */
      png_set_benign_errors(write_ptr, 0);

      /* if strict is not set, then both are treated as warnings. */
   }

759
   pngtest_debug("Initializing input and output streams");
760
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
761
   png_init_io(read_ptr, fpin);
762
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
763
   png_init_io(write_ptr, fpout);
764
#  endif
765
#else
766
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
767
#  ifdef PNG_WRITE_SUPPORTED
768
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
769
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
770
      pngtest_flush);
771
#    else
772
      NULL);
773 774
#    endif
#  endif
775
#endif
776

777
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
778 779
   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
    * This is here just to make pngtest replicate the results from libpng
780
    * versions prior to 1.5.4, and to test this new API.
781
    */
782 783 784
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

785
   if (status_dots_requested == 1)
786
   {
787
#ifdef PNG_WRITE_SUPPORTED
788
      png_set_write_status_fn(write_ptr, write_row_callback);
789
#endif
790 791
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
792

793 794
   else
   {
795
#ifdef PNG_WRITE_SUPPORTED
796
      png_set_write_status_fn(write_ptr, NULL);
797
#endif
798
      png_set_read_status_fn(read_ptr, NULL);
799 800
   }

801
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
802
   {
803
      int i;
804

805 806
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
807

808
      png_set_read_user_transform_fn(read_ptr, count_filters);
809 810
   }
#endif
811
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
812
   zero_samples = 0;
813 814
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
815

816
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
817 818 819
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
820 821
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
822
#endif
823
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
824 825 826
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
827 828
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
829 830
#endif

831
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
832
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
833

834
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
835 836
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
837

A
Andreas Dilger 已提交
838 839 840 841
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
842
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
843
            color_type, interlace_type, compression_type, filter_type);
844 845 846
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
847 848
      }
   }
849 850
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
851
   {
852
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
853
         blue_y;
854

855 856
      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
         &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y))
A
Andreas Dilger 已提交
857
      {
858 859
         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
A
Andreas Dilger 已提交
860
      }
G
Guy Schalnat 已提交
861
   }
A
Andreas Dilger 已提交
862
#endif
863
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
864
   {
865
      png_fixed_point gamma;
G
Guy Schalnat 已提交
866

867 868
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
869 870
   }
#endif
871
#else /* Use floating point versions */
872 873
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
874 875 876
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
877

878 879 880 881 882 883 884 885
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
886
#ifdef PNG_gAMA_SUPPORTED
887 888 889 890 891 892 893
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
894 895
#endif /* Floating point */
#endif /* Fixed point */
896
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
897
   {
898
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
899
      png_bytep profile;
900
      png_uint_32 proflen;
901
      int compression_type;
A
Andreas Dilger 已提交
902

903 904
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
905
      {
906 907
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
908
      }
G
Guy Schalnat 已提交
909
   }
910
#endif
911
#ifdef PNG_sRGB_SUPPORTED
912
   {
913
      int intent;
914 915 916 917

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
918
#endif
919 920 921 922 923 924 925
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
   }
926
#ifdef PNG_bKGD_SUPPORTED
927 928 929 930 931 932 933 934 935
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
936
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
937
   {
A
Andreas Dilger 已提交
938 939 940 941
      png_uint_16p hist;

      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
         png_set_hIST(write_ptr, write_info_ptr, hist);
G
Guy Schalnat 已提交
942
   }
A
Andreas Dilger 已提交
943
#endif
944
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
945
   {
946
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
947
      int unit_type;
G
Guy Schalnat 已提交
948

949
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
950
          &unit_type))
A
Andreas Dilger 已提交
951 952 953 954 955
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
956
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
957 958 959 960 961 962 963 964 965 966 967 968 969 970
   {
      png_charp purpose, units;
      png_charpp params;
      png_int_32 X0, X1;
      int type, nparams;

      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
         &nparams, &units, &params))
      {
         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
            nparams, units, params);
      }
   }
#endif
971
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
972 973 974 975 976 977 978 979
   {
      png_uint_32 res_x, res_y;
      int unit_type;

      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
   }
#endif
980
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
981
   {
982
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
983

984 985
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
986
   }
987
#endif
988
#ifdef PNG_sCAL_SUPPORTED
989
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
990
   {
991
      int unit;
992
      double scal_width, scal_height;
A
Andreas Dilger 已提交
993

994 995
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
996
      {
997
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
998 999 1000
      }
   }
#else
1001
#ifdef PNG_FIXED_POINT_SUPPORTED
1002
   {
1003
      int unit;
1004
      png_charp scal_width, scal_height;
1005

1006 1007
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1008
      {
1009 1010
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1011 1012
      }
   }
G
Guy Schalnat 已提交
1013
#endif
1014 1015
#endif
#endif
1016
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1017 1018 1019 1020 1021 1022
   {
      png_textp text_ptr;
      int num_text;

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

         if (verbose)
1026
            printf("\n Text compression=%d\n", text_ptr->compression);
1027

A
Andreas Dilger 已提交
1028 1029 1030 1031
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1032
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1033 1034 1035 1036 1037 1038
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1039
#ifdef PNG_TIME_RFC1123_SUPPORTED
1040 1041 1042 1043 1044
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

         else
            strcpy(tIME_string, "*** invalid time ***");
1045

1046 1047
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1048
      }
A
Andreas Dilger 已提交
1049 1050
   }
#endif
1051
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1052
   {
1053
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1054
      int num_trans;
1055
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1056

1057
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1058
         &trans_color))
A
Andreas Dilger 已提交
1059
      {
1060
         int sample_max = (1 << bit_depth);
1061
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1062
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1063
             (int)trans_color->gray > sample_max) ||
1064
             (color_type == PNG_COLOR_TYPE_RGB &&
1065 1066 1067
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1068
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1069
               trans_color);
A
Andreas Dilger 已提交
1070 1071 1072
      }
   }
#endif
1073
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1074 1075
   {
      png_unknown_chunkp unknowns;
1076
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1077
         &unknowns);
1078

1079 1080
      if (num_unknowns)
      {
1081
         int i;
1082 1083
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1084
         /* Copy the locations from the read_info_ptr.  The automatically
1085 1086 1087
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1088
         for (i = 0; i < num_unknowns; i++)
1089 1090
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1091 1092 1093
      }
   }
#endif
A
Andreas Dilger 已提交
1094

1095
#ifdef PNG_WRITE_SUPPORTED
1096
   pngtest_debug("Writing info struct");
1097 1098

/* If we wanted, we could write info in two steps:
1099
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1100
 */
A
Andreas Dilger 已提交
1101
   png_write_info(write_ptr, write_info_ptr);
1102

1103
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1104 1105
   if (user_chunk_data[0] != 0)
   {
1106
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1107

1108 1109
      unsigned char
        ster_chunk_data[1];
1110

1111 1112 1113
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1114

1115 1116
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1117
   }
1118

1119 1120
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
      png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};

      unsigned char
        vpag_chunk_data[9];

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

1132 1133 1134 1135
      png_save_uint_32(vpag_chunk_data, user_chunk_data[1]);
      png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]);
      vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff);
      png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
1136 1137 1138
   }

#endif
1139
#endif
A
Andreas Dilger 已提交
1140

1141
#ifdef SINGLE_ROWBUF_ALLOC
1142
   pngtest_debug("Allocating row buffer...");
1143
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1144
      png_get_rowbytes(read_ptr, read_info_ptr));
1145

1146
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1147
#endif /* SINGLE_ROWBUF_ALLOC */
1148
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1149

1150 1151
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1152
   num_pass = png_set_interlace_handling(read_ptr);
1153
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1154
   png_set_interlace_handling(write_ptr);
1155
#  endif
1156
#else
1157
   num_pass = 1;
1158
#endif
A
Andreas Dilger 已提交
1159

1160 1161 1162 1163 1164
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1165 1166
   for (pass = 0; pass < num_pass; pass++)
   {
1167
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1168 1169
      for (y = 0; y < height; y++)
      {
1170
#ifndef SINGLE_ROWBUF_ALLOC
1171
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1172 1173
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1174

1175
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1176
            png_get_rowbytes(read_ptr, read_info_ptr));
1177

1178
#endif /* !SINGLE_ROWBUF_ALLOC */
1179
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1180 1181

#ifdef PNG_WRITE_SUPPORTED
1182 1183 1184 1185 1186
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1187
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1188 1189 1190 1191 1192
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1193 1194 1195
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1196
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1197
         png_free(read_ptr, row_buf);
1198
         row_buf = NULL;
1199
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1200 1201 1202
      }
   }

1203
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1204
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1205
#endif
1206
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1207
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1208 1209
#endif

1210
   pngtest_debug("Reading and writing end_info data");
1211

A
Andreas Dilger 已提交
1212
   png_read_end(read_ptr, end_info_ptr);
1213
#ifdef PNG_TEXT_SUPPORTED
1214 1215 1216 1217 1218 1219
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1220
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1221 1222 1223 1224
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1225
#ifdef PNG_tIME_SUPPORTED
1226 1227 1228 1229 1230 1231
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1232
#ifdef PNG_TIME_RFC1123_SUPPORTED
1233 1234 1235 1236 1237
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

         else
            strcpy(tIME_string, "*** invalid time ***");
1238

1239 1240 1241 1242
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1243
#endif
1244
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1245 1246
   {
      png_unknown_chunkp unknowns;
1247
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1248
         &unknowns);
1249

1250 1251
      if (num_unknowns)
      {
1252
         int i;
1253 1254
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1255
         /* Copy the locations from the read_info_ptr.  The automatically
1256 1257 1258
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1259
         for (i = 0; i < num_unknowns; i++)
1260 1261
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1262 1263
      }
   }
1264
#endif
1265
#ifdef PNG_WRITE_SUPPORTED
1266
   png_write_end(write_ptr, write_end_info_ptr);
1267
#endif
1268

1269
#ifdef PNG_EASY_ACCESS_SUPPORTED
1270
   if (verbose)
1271 1272 1273 1274
   {
      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);
1275
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1276
         (unsigned long)iwidth, (unsigned long)iheight);
1277 1278
   }
#endif
G
Guy Schalnat 已提交
1279

1280
   pngtest_debug("Destroying data structs");
1281
#ifdef SINGLE_ROWBUF_ALLOC
1282
   pngtest_debug("destroying row_buf for read_ptr");
1283
   png_free(read_ptr, row_buf);
1284
   row_buf = NULL;
1285
#endif /* SINGLE_ROWBUF_ALLOC */
1286
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1287
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1288
#ifdef PNG_WRITE_SUPPORTED
1289
   pngtest_debug("destroying write_end_info_ptr");
1290
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1291
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1292
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1293
#endif
1294
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1295

1296 1297
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1298

1299
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1300
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1301
   {
G
Guy Schalnat 已提交
1302
      fprintf(STDERR, "Could not find file %s\n", inname);
1303
      return (1);
G
Guy Schalnat 已提交
1304 1305
   }

A
Andreas Dilger 已提交
1306
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1307
   {
G
Guy Schalnat 已提交
1308
      fprintf(STDERR, "Could not find file %s\n", outname);
1309
      FCLOSE(fpin);
1310
      return (1);
G
Guy Schalnat 已提交
1311
   }
A
Andreas Dilger 已提交
1312

1313
   for (;;)
G
Guy Schalnat 已提交
1314
   {
A
Andreas Dilger 已提交
1315
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1316

1317 1318
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1319 1320 1321

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

1325
         if (wrote_question == 0)
1326 1327
         {
            fprintf(STDERR,
1328
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1329
              inname, PNG_ZBUF_SIZE);
1330
            fprintf(STDERR,
1331
              "\n   filtering heuristic (libpng default), compression");
1332
            fprintf(STDERR,
1333
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1334
              ZLIB_VERSION);
1335
            wrote_question = 1;
1336
         }
1337

1338 1339
         FCLOSE(fpin);
         FCLOSE(fpout);
1340 1341 1342 1343 1344 1345

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

         else
           return (0);
G
Guy Schalnat 已提交
1346 1347 1348 1349 1350
      }

      if (!num_in)
         break;

1351
      if (memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1352
      {
1353
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1354

1355
         if (wrote_question == 0)
1356 1357
         {
            fprintf(STDERR,
1358
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1359
                 inname, PNG_ZBUF_SIZE);
1360
            fprintf(STDERR,
1361
              "\n   filtering heuristic (libpng default), compression");
1362
            fprintf(STDERR,
1363
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1364
              ZLIB_VERSION);
1365
            wrote_question = 1;
1366
         }
1367

1368 1369
         FCLOSE(fpin);
         FCLOSE(fpout);
1370 1371 1372 1373 1374 1375

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

         else
           return (0);
G
Guy Schalnat 已提交
1376 1377 1378
      }
   }

1379 1380
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1381

1382
   return (0);
G
Guy Schalnat 已提交
1383
}
G
Guy Schalnat 已提交
1384

1385
/* Input and output filenames */
1386
#ifdef RISCOS
1387 1388
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1389
#else
1390 1391
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1392 1393 1394 1395 1396 1397 1398 1399
#endif

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

1400
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1401
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1402
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1403
   /* Show the version of libpng used in building the library */
1404 1405
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1406
      png_get_header_version(NULL));
1407

1408
   /* Show the version of libpng used in building the application */
1409
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1410
      PNG_HEADER_VERSION_STRING);
1411 1412

   /* Do some consistency checking on the memory allocation settings, I'm
1413 1414 1415 1416
    * 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
    */
1417
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1418
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1419
#endif
1420
   /* I think the following can happen. */
1421
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1422
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1423
#endif
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435

   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
   {
      fprintf(STDERR,
         "Warning: versions are different between png.h and png.c\n");
      fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
      fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
      ++ierror;
   }

   if (argc > 1)
   {
1436
      if (strcmp(argv[1], "-m") == 0)
1437
      {
1438
         multiple = 1;
1439 1440
         status_dots_requested = 0;
      }
1441

1442 1443 1444 1445 1446
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1447
         status_dots_requested = 1;
1448
      }
1449

1450 1451 1452
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1453
         status_dots_requested = 1;
1454 1455
         inname = argv[2];
      }
1456

1457 1458 1459 1460 1461 1462 1463 1464
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
      }

1465
      else
1466
      {
1467
         inname = argv[1];
1468 1469
         status_dots_requested = 0;
      }
1470 1471
   }

1472 1473
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1474

1475
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1476
   {
1477 1478
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1479
        argv[0], argv[0]);
1480 1481 1482 1483
     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);
1484 1485 1486 1487 1488 1489
     exit(1);
   }

   if (multiple)
   {
      int i;
1490
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1491 1492
      int allocation_now = current_allocation;
#endif
1493
      for (i=2; i<argc; ++i)
1494
      {
1495
         int kerror;
1496
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1497
         kerror = test_one_file(argv[i], outname);
1498
         if (kerror == 0)
1499
         {
1500 1501 1502
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1503
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1504
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1505
               (unsigned long)zero_samples);
1506
#else
1507
            fprintf(STDERR, " PASS\n");
1508
#endif
1509
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1510 1511
            for (k = 0; k<256; k++)
               if (filters_used[k])
1512
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1513
                     k, (unsigned long)filters_used[k]);
1514
#endif
1515
#ifdef PNG_TIME_RFC1123_SUPPORTED
1516 1517
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1518

1519 1520 1521
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1522

1523 1524
         else
         {
1525 1526
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1527
         }
1528
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1529 1530
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1531
               current_allocation - allocation_now);
1532

1533 1534
         if (current_allocation != 0)
         {
1535 1536 1537 1538
            memory_infop pinfo = pinformation;

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

1540 1541
            while (pinfo != NULL)
            {
1542
               fprintf(STDERR, " %lu bytes at %x\n",
1543
                 (unsigned long)pinfo->size,
1544
                 (unsigned int)pinfo->pointer);
1545
               pinfo = pinfo->next;
1546
            }
1547
         }
1548 1549
#endif
      }
1550
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1551
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1552
            current_allocation);
1553
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1554
            maximum_allocation);
1555 1556 1557 1558
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1559
#endif
1560
   }
1561

1562 1563
   else
   {
1564
      int i;
1565
      for (i = 0; i<3; ++i)
1566
      {
1567
         int kerror;
1568
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1569 1570
         int allocation_now = current_allocation;
#endif
1571 1572 1573 1574 1575 1576
         if (i == 1)
            status_dots_requested = 1;

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

1577
         if (i == 0 || verbose == 1 || ierror != 0)
1578
            fprintf(STDERR, "\n Testing %s:", inname);
1579

1580
         kerror = test_one_file(inname, outname);
1581

1582
         if (kerror == 0)
1583
         {
1584
            if (verbose == 1 || i == 2)
1585
            {
1586
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1587
                int k;
1588
#endif
1589
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1590
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1591
                   (unsigned long)zero_samples);
1592 1593 1594
#else
                fprintf(STDERR, " PASS\n");
#endif
1595
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1596 1597
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1598
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1599
                         k, (unsigned long)filters_used[k]);
1600
#endif
1601
#ifdef PNG_TIME_RFC1123_SUPPORTED
1602 1603
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1604 1605
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1606
         }
1607

1608 1609
         else
         {
1610
            if (verbose == 0 && i != 2)
1611
               fprintf(STDERR, "\n Testing %s:", inname);
1612

1613 1614
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1615
         }
1616
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1617 1618
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1619
               current_allocation - allocation_now);
1620

1621 1622
         if (current_allocation != 0)
         {
1623
             memory_infop pinfo = pinformation;
1624

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

1628 1629
             while (pinfo != NULL)
             {
1630 1631
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1632 1633 1634 1635
                pinfo = pinfo->next;
             }
          }
#endif
1636
       }
1637
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1638
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1639
          current_allocation);
1640
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1641
          maximum_allocation);
1642 1643 1644 1645
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1646
#endif
1647 1648
   }

1649 1650 1651 1652
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1653
   fprintf(STDERR, " CPU time used = %.3f seconds",
1654
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1655
   fprintf(STDERR, " (decoding %.3f,\n",
1656
      t_decode/(float)CLOCKS_PER_SEC);
1657
   fprintf(STDERR, "        encoding %.3f ,",
1658
      t_encode/(float)CLOCKS_PER_SEC);
1659
   fprintf(STDERR, " other %.3f seconds)\n\n",
1660 1661 1662
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1663
   if (ierror == 0)
1664
      fprintf(STDERR, " libpng passes test\n");
1665

1666
   else
1667
      fprintf(STDERR, " libpng FAILS test\n");
1668

1669
   return (int)(ierror != 0);
1670
}
1671

1672
/* Generate a compiler error if there is an old png.h in the search path. */
1673
typedef png_libpng_version_1_6_0beta18 Your_png_h_is_not_version_1_6_0beta18;