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

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * Last changed in libpng 1.6.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 1027 1028 1029 1030 1031 1032 1033 1034 1035
         {
            int i;

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

A
Andreas Dilger 已提交
1037 1038 1039 1040
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1041
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1042 1043 1044 1045 1046 1047
   {
      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);
1048
#ifdef PNG_TIME_RFC1123_SUPPORTED
1049 1050 1051 1052
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

         else
1053 1054 1055 1056
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1057

1058 1059
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1060
      }
A
Andreas Dilger 已提交
1061 1062
   }
#endif
1063
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1064
   {
1065
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1066
      int num_trans;
1067
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1068

1069
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1070
         &trans_color))
A
Andreas Dilger 已提交
1071
      {
1072
         int sample_max = (1 << bit_depth);
1073
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1074
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1075
             (int)trans_color->gray > sample_max) ||
1076
             (color_type == PNG_COLOR_TYPE_RGB &&
1077 1078 1079
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1080
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1081
               trans_color);
A
Andreas Dilger 已提交
1082 1083 1084
      }
   }
#endif
1085
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1086 1087
   {
      png_unknown_chunkp unknowns;
1088
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1089
         &unknowns);
1090

1091 1092
      if (num_unknowns)
      {
1093
         int i;
1094 1095
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1096
         /* Copy the locations from the read_info_ptr.  The automatically
1097 1098 1099
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1100
         for (i = 0; i < num_unknowns; i++)
1101 1102
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1103 1104 1105
      }
   }
#endif
A
Andreas Dilger 已提交
1106

1107
#ifdef PNG_WRITE_SUPPORTED
1108
   pngtest_debug("Writing info struct");
1109 1110

/* If we wanted, we could write info in two steps:
1111
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1112
 */
A
Andreas Dilger 已提交
1113
   png_write_info(write_ptr, write_info_ptr);
1114

1115
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1116 1117
   if (user_chunk_data[0] != 0)
   {
1118
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1119

1120 1121
      unsigned char
        ster_chunk_data[1];
1122

1123 1124 1125
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1126

1127 1128
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1129
   }
1130

1131 1132
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
      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]);
1143

1144 1145 1146 1147
      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);
1148 1149 1150
   }

#endif
1151
#endif
A
Andreas Dilger 已提交
1152

1153
#ifdef SINGLE_ROWBUF_ALLOC
1154
   pngtest_debug("Allocating row buffer...");
1155
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1156
      png_get_rowbytes(read_ptr, read_info_ptr));
1157

1158
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1159
#endif /* SINGLE_ROWBUF_ALLOC */
1160
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1161

1162 1163
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1164
   num_pass = png_set_interlace_handling(read_ptr);
1165
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1166
   png_set_interlace_handling(write_ptr);
1167
#  endif
1168
#else
1169
   num_pass = 1;
1170
#endif
A
Andreas Dilger 已提交
1171

1172 1173 1174 1175 1176
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1177 1178
   for (pass = 0; pass < num_pass; pass++)
   {
1179
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1180 1181
      for (y = 0; y < height; y++)
      {
1182
#ifndef SINGLE_ROWBUF_ALLOC
1183
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1184 1185
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1186

1187
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1188
            png_get_rowbytes(read_ptr, read_info_ptr));
1189

1190
#endif /* !SINGLE_ROWBUF_ALLOC */
1191
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1192 1193

#ifdef PNG_WRITE_SUPPORTED
1194 1195 1196 1197 1198
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1199
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1200 1201 1202 1203 1204
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1205 1206 1207
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1208
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1209
         png_free(read_ptr, row_buf);
1210
         row_buf = NULL;
1211
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1212 1213 1214
      }
   }

1215
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1216
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1217
#endif
1218
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1219
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1220 1221
#endif

1222
   pngtest_debug("Reading and writing end_info data");
1223

A
Andreas Dilger 已提交
1224
   png_read_end(read_ptr, end_info_ptr);
1225
#ifdef PNG_TEXT_SUPPORTED
1226 1227 1228 1229 1230 1231
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1232
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245

         if (verbose)
         {
            int i;

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

1246 1247 1248 1249
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1250
#ifdef PNG_tIME_SUPPORTED
1251 1252 1253 1254 1255 1256
   {
      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);
1257
#ifdef PNG_TIME_RFC1123_SUPPORTED
1258 1259 1260 1261
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

         else
1262 1263 1264 1265
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1266

1267 1268 1269 1270
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1271
#endif
1272
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1273 1274
   {
      png_unknown_chunkp unknowns;
1275
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1276
         &unknowns);
1277

1278 1279
      if (num_unknowns)
      {
1280
         int i;
1281 1282
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1283
         /* Copy the locations from the read_info_ptr.  The automatically
1284 1285 1286
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1287
         for (i = 0; i < num_unknowns; i++)
1288 1289
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1290 1291
      }
   }
1292
#endif
1293
#ifdef PNG_WRITE_SUPPORTED
1294
   png_write_end(write_ptr, write_end_info_ptr);
1295
#endif
1296

1297
#ifdef PNG_EASY_ACCESS_SUPPORTED
1298
   if (verbose)
1299 1300 1301 1302
   {
      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);
1303
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1304
         (unsigned long)iwidth, (unsigned long)iheight);
1305 1306
   }
#endif
G
Guy Schalnat 已提交
1307

1308
   pngtest_debug("Destroying data structs");
1309
#ifdef SINGLE_ROWBUF_ALLOC
1310
   pngtest_debug("destroying row_buf for read_ptr");
1311
   png_free(read_ptr, row_buf);
1312
   row_buf = NULL;
1313
#endif /* SINGLE_ROWBUF_ALLOC */
1314
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1315
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1316
#ifdef PNG_WRITE_SUPPORTED
1317
   pngtest_debug("destroying write_end_info_ptr");
1318
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1319
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1320
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1321
#endif
1322
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1323

1324 1325
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1326

1327
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1328
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1329
   {
G
Guy Schalnat 已提交
1330
      fprintf(STDERR, "Could not find file %s\n", inname);
1331
      return (1);
G
Guy Schalnat 已提交
1332 1333
   }

A
Andreas Dilger 已提交
1334
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1335
   {
G
Guy Schalnat 已提交
1336
      fprintf(STDERR, "Could not find file %s\n", outname);
1337
      FCLOSE(fpin);
1338
      return (1);
G
Guy Schalnat 已提交
1339
   }
A
Andreas Dilger 已提交
1340

1341
   for (;;)
G
Guy Schalnat 已提交
1342
   {
A
Andreas Dilger 已提交
1343
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1344

1345 1346
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1347 1348 1349

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

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

1366 1367
         FCLOSE(fpin);
         FCLOSE(fpout);
1368 1369 1370 1371 1372 1373

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

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

      if (!num_in)
         break;

1379
      if (memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1380
      {
1381
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1382

1383
         if (wrote_question == 0)
1384 1385
         {
            fprintf(STDERR,
1386
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1387
                 inname, PNG_ZBUF_SIZE);
1388
            fprintf(STDERR,
1389
              "\n   filtering heuristic (libpng default), compression");
1390
            fprintf(STDERR,
1391
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1392
              ZLIB_VERSION);
1393
            wrote_question = 1;
1394
         }
1395

1396 1397
         FCLOSE(fpin);
         FCLOSE(fpout);
1398 1399 1400 1401 1402 1403

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

         else
           return (0);
G
Guy Schalnat 已提交
1404 1405 1406
      }
   }

1407 1408
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1409

1410
   return (0);
G
Guy Schalnat 已提交
1411
}
G
Guy Schalnat 已提交
1412

1413
/* Input and output filenames */
1414
#ifdef RISCOS
1415 1416
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1417
#else
1418 1419
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1420 1421 1422 1423 1424 1425 1426 1427
#endif

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

1428
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1429
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1430
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1431
   /* Show the version of libpng used in building the library */
1432 1433
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1434
      png_get_header_version(NULL));
1435

1436
   /* Show the version of libpng used in building the application */
1437
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1438
      PNG_HEADER_VERSION_STRING);
1439 1440

   /* Do some consistency checking on the memory allocation settings, I'm
1441 1442 1443 1444
    * 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
    */
1445
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1446
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1447
#endif
1448
   /* I think the following can happen. */
1449
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1450
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1451
#endif
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463

   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)
   {
1464
      if (strcmp(argv[1], "-m") == 0)
1465
      {
1466
         multiple = 1;
1467 1468
         status_dots_requested = 0;
      }
1469

1470 1471 1472 1473 1474
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1475
         status_dots_requested = 1;
1476
      }
1477

1478 1479 1480
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1481
         status_dots_requested = 1;
1482 1483
         inname = argv[2];
      }
1484

1485 1486 1487 1488 1489 1490 1491 1492
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
      }

1493
      else
1494
      {
1495
         inname = argv[1];
1496 1497
         status_dots_requested = 0;
      }
1498 1499
   }

1500 1501
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1502

1503
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1504
   {
1505 1506
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1507
        argv[0], argv[0]);
1508 1509 1510 1511
     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);
1512 1513 1514 1515 1516 1517
     exit(1);
   }

   if (multiple)
   {
      int i;
1518
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1519 1520
      int allocation_now = current_allocation;
#endif
1521
      for (i=2; i<argc; ++i)
1522
      {
1523
         int kerror;
1524
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1525
         kerror = test_one_file(argv[i], outname);
1526
         if (kerror == 0)
1527
         {
1528 1529 1530
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1531
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1532
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1533
               (unsigned long)zero_samples);
1534
#else
1535
            fprintf(STDERR, " PASS\n");
1536
#endif
1537
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1538 1539
            for (k = 0; k<256; k++)
               if (filters_used[k])
1540
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1541
                     k, (unsigned long)filters_used[k]);
1542
#endif
1543
#ifdef PNG_TIME_RFC1123_SUPPORTED
1544 1545
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1546

1547 1548 1549
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1550

1551 1552
         else
         {
1553 1554
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1555
         }
1556
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1557 1558
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1559
               current_allocation - allocation_now);
1560

1561 1562
         if (current_allocation != 0)
         {
1563 1564 1565 1566
            memory_infop pinfo = pinformation;

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

1568 1569
            while (pinfo != NULL)
            {
1570
               fprintf(STDERR, " %lu bytes at %x\n",
1571
                 (unsigned long)pinfo->size,
1572
                 (unsigned int)pinfo->pointer);
1573
               pinfo = pinfo->next;
1574
            }
1575
         }
1576 1577
#endif
      }
1578
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1579
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1580
            current_allocation);
1581
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1582
            maximum_allocation);
1583 1584 1585 1586
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1587
#endif
1588
   }
1589

1590 1591
   else
   {
1592
      int i;
1593
      for (i = 0; i<3; ++i)
1594
      {
1595
         int kerror;
1596
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1597 1598
         int allocation_now = current_allocation;
#endif
1599 1600 1601 1602 1603 1604
         if (i == 1)
            status_dots_requested = 1;

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

1605
         if (i == 0 || verbose == 1 || ierror != 0)
1606
            fprintf(STDERR, "\n Testing %s:", inname);
1607

1608
         kerror = test_one_file(inname, outname);
1609

1610
         if (kerror == 0)
1611
         {
1612
            if (verbose == 1 || i == 2)
1613
            {
1614
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1615
                int k;
1616
#endif
1617
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1618
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1619
                   (unsigned long)zero_samples);
1620 1621 1622
#else
                fprintf(STDERR, " PASS\n");
#endif
1623
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1624 1625
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1626
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1627
                         k, (unsigned long)filters_used[k]);
1628
#endif
1629
#ifdef PNG_TIME_RFC1123_SUPPORTED
1630 1631
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1632 1633
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1634
         }
1635

1636 1637
         else
         {
1638
            if (verbose == 0 && i != 2)
1639
               fprintf(STDERR, "\n Testing %s:", inname);
1640

1641 1642
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1643
         }
1644
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1645 1646
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1647
               current_allocation - allocation_now);
1648

1649 1650
         if (current_allocation != 0)
         {
1651
             memory_infop pinfo = pinformation;
1652

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

1656 1657
             while (pinfo != NULL)
             {
1658 1659
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1660 1661 1662 1663
                pinfo = pinfo->next;
             }
          }
#endif
1664
       }
1665
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1666
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1667
          current_allocation);
1668
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1669
          maximum_allocation);
1670 1671 1672 1673
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1674
#endif
1675 1676
   }

1677 1678 1679 1680
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1681
   fprintf(STDERR, " CPU time used = %.3f seconds",
1682
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1683
   fprintf(STDERR, " (decoding %.3f,\n",
1684
      t_decode/(float)CLOCKS_PER_SEC);
1685
   fprintf(STDERR, "        encoding %.3f ,",
1686
      t_encode/(float)CLOCKS_PER_SEC);
1687
   fprintf(STDERR, " other %.3f seconds)\n\n",
1688 1689 1690
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1691
   if (ierror == 0)
1692
      fprintf(STDERR, " libpng passes test\n");
1693

1694
   else
1695
      fprintf(STDERR, " libpng FAILS test\n");
1696

1697
   return (int)(ierror != 0);
1698
}
1699

1700
/* Generate a compiler error if there is an old png.h in the search path. */
1701
typedef png_libpng_version_1_6_0beta27 Your_png_h_is_not_version_1_6_0beta27;