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

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

34 35
#define _POSIX_SOURCE 1

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

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

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

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

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

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

92
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
93

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

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

102 103 104 105 106
/* 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

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

112
void PNGCBAPI
113
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
114
void PNGCBAPI
115
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
116
{
117 118
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
119

120 121 122 123 124 125
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
126

127
   status_dots--;
128

129 130 131 132 133
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
134

135
   fprintf(stdout, "r");
136
}
137

138
void PNGCBAPI
139
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
140
void PNGCBAPI
141
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
142
{
143 144
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
145

146
   fprintf(stdout, "w");
147 148 149
}


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

166
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
167
/* Example of using user transform callback (we don't transform anything,
168 169
 * but merely count the zero samples)
 */
170

171
static png_uint_32 zero_samples;
172

173
void PNGCBAPI
174
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
175
void PNGCBAPI
176
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
177 178
{
   png_bytep dp = data;
179 180
   if (png_ptr == NULL)
      return;
181

182
   /* Contents of row_info:
183 184 185 186 187 188 189 190
    *  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)
    */

191
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
192

193
    if (row_info->color_type == 0 || row_info->color_type == 3)
194
    {
195
       int pos = 0;
196
       png_uint_32 n, nstop;
197

198
       for (n = 0, nstop=row_info->width; n<nstop; n++)
199
       {
200
          if (row_info->bit_depth == 1)
201
          {
202 203
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
204

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

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

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

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

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

236
          if (row_info->bit_depth == 8)
237 238
             if (*dp++ == 0)
                zero_samples++;
239

240
          if (row_info->bit_depth == 16)
241
          {
242 243
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
244 245 246 247
             dp+=2;
          }
       }
    }
248
    else /* Other color types */
249
    {
250
       png_uint_32 n, nstop;
251 252
       int channel;
       int color_channels = row_info->channels;
253
       if (row_info->color_type > 3)color_channels--;
254

255
       for (n = 0, nstop=row_info->width; n<nstop; n++)
256 257 258
       {
          for (channel = 0; channel < color_channels; channel++)
          {
259
             if (row_info->bit_depth == 8)
260 261
                if (*dp++ == 0)
                   zero_samples++;
262

263
             if (row_info->bit_depth == 16)
264
             {
265 266
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
267

268 269 270
                dp+=2;
             }
          }
271
          if (row_info->color_type > 3)
272 273
          {
             dp++;
274 275
             if (row_info->bit_depth == 16)
                dp++;
276 277 278 279
          }
       }
    }
}
280
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
281

282
static int wrote_question = 0;
283

284
#ifndef PNG_STDIO_SUPPORTED
285
/* START of code to validate stdio-free compilation */
286 287 288 289 290 291 292
/* 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.
 */
293

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
#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

336
static void PNGCBAPI
337
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
338
{
339 340
   png_size_t check = 0;
   png_voidp io_ptr;
341 342 343 344

   /* 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.
    */
345 346 347 348 349
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
350

351 352
   if (check != length)
   {
353
      png_error(png_ptr, "Read Error");
354
   }
355 356 357 358

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

361
#ifdef PNG_WRITE_FLUSH_SUPPORTED
362
static void PNGCBAPI
363
pngtest_flush(png_structp png_ptr)
364
{
365
   /* Do nothing; fflush() is said to be just a waste of energy. */
366
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
367 368
}
#endif
G
Guy Schalnat 已提交
369

370
/* This is the function that does the actual writing of data.  If you are
371 372 373 374
 * 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.
 */
375
static void PNGCBAPI
376
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
377
{
378
   png_size_t check;
379

380
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
381

382 383 384 385
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
386 387 388 389

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
390 391 392 393 394 395 396
}

/* 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.
 */
397
static void PNGCBAPI
398
pngtest_warning(png_structp png_ptr, png_const_charp message)
399 400
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
401 402
   char *test;
   test = png_get_error_ptr(png_ptr);
403

404 405
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
406

407 408
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
409 410 411 412 413 414 415
}

/* 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().
 */
416
static void PNGCBAPI
417
pngtest_error(png_structp png_ptr, png_const_charp message)
418
{
419
   pngtest_warning(png_ptr, message);
420
   /* We can return because png_error calls the default handler, which is
421 422
    * actually OK in this case.
    */
423
}
424
#endif /* !PNG_STDIO_SUPPORTED */
425 426
/* END of code to validate stdio-free compilation */

427
/* START of code to validate memory allocation and deallocation */
428
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
429 430

/* Allocate memory.  For reasonable files, size should never exceed
431 432 433 434 435 436 437 438
 * 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.
 */
439 440
typedef struct memory_information
{
441
   png_alloc_size_t          size;
442
   png_voidp                 pointer;
443
   struct memory_information *next;
444
} memory_information;
445
typedef memory_information *memory_infop;
446 447 448 449

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
450 451
static int total_allocation = 0;
static int num_allocations = 0;
452

453 454 455
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));
456 457

png_voidp
458
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
459
{
460

461
   /* png_malloc has already tested for NULL; png_create_struct calls
462 463
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
464

465
   if (size == 0)
466
      return (NULL);
467 468 469 470

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
471
      /* Disable malloc_fn and free_fn */
472
      memory_infop pinfo;
473
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
474 475
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
476 477
      pinfo->size = size;
      current_allocation += size;
478 479
      total_allocation += size;
      num_allocations ++;
480

481 482
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
483

484
      pinfo->pointer = png_malloc(png_ptr, size);
485
      /* Restore malloc_fn and free_fn */
486

487 488
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
489

490 491 492 493
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
494
         png_error(png_ptr,
495
           "out of memory in pngtest->png_debug_malloc");
496
      }
497

498 499 500
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
501
      memset(pinfo->pointer, 0xdd, pinfo->size);
502

503
      if (verbose)
504
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
505
            pinfo->pointer);
506

507
      return (png_voidp)(pinfo->pointer);
508 509 510 511
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
512
void PNGCBAPI
513
png_debug_free(png_structp png_ptr, png_voidp ptr)
514 515
{
   if (png_ptr == NULL)
516
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
517

518 519
   if (ptr == 0)
   {
520 521 522 523 524 525 526 527
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
528
      memory_infop *ppinfo = &pinformation;
529

530 531
      for (;;)
      {
532
         memory_infop pinfo = *ppinfo;
533

534 535
         if (pinfo->pointer == ptr)
         {
536 537 538 539 540
            *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
541
               the memory that is to be freed. */
542
            memset(ptr, 0x55, pinfo->size);
543
            png_free_default(png_ptr, pinfo);
544
            pinfo = NULL;
545 546
            break;
         }
547

548 549
         if (pinfo->next == NULL)
         {
550
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
551 552
            break;
         }
553

554 555 556 557 558
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
559
   if (verbose)
560
      printf("Freeing %p\n", ptr);
561

562
   png_free_default(png_ptr, ptr);
563
   ptr = NULL;
564
}
565
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
566 567
/* END of code to test memory allocation/deallocation */

568 569

/* Demonstration of user chunk support of the sTER and vpAg chunks */
570
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
571

572
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
573 574 575 576
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

577 578 579 580
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
581 582
     */

583
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
584 585
   png_unknown_chunkp chunk)
{
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607
   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 */
608

609 610
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
611

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
         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);
633 634 635 636 637

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

638
/* Test one file */
639 640
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
641
{
642 643
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
644 645 646 647 648 649 650 651 652 653 654
   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 已提交
655
   png_bytep row_buf;
G
Guy Schalnat 已提交
656
   png_uint_32 y;
A
Andreas Dilger 已提交
657 658 659
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
660

661
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
662

663
   row_buf = NULL;
G
Guy Schalnat 已提交
664

A
Andreas Dilger 已提交
665
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
666 667
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
668
      return (1);
G
Guy Schalnat 已提交
669 670
   }

A
Andreas Dilger 已提交
671
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
672
   {
G
Guy Schalnat 已提交
673
      fprintf(STDERR, "Could not open output file %s\n", outname);
674
      FCLOSE(fpin);
675
      return (1);
G
Guy Schalnat 已提交
676 677
   }

678
   pngtest_debug("Allocating read and write structures");
679
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
680 681
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
682
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
683
#else
684 685
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
686
#endif
687
#ifndef PNG_STDIO_SUPPORTED
688 689
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
690
#endif
691

692
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
693 694 695 696 697 698
   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);
699

700
#endif
701
#ifdef PNG_WRITE_SUPPORTED
702
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
703 704 705
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
706
#else
707 708
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
709
#endif
710
#ifndef PNG_STDIO_SUPPORTED
711 712
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
713
#endif
714
#endif
715
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
716
   read_info_ptr = png_create_info_struct(read_ptr);
717
   end_info_ptr = png_create_info_struct(read_ptr);
718 719
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
720
   write_end_info_ptr = png_create_info_struct(write_ptr);
721
#endif
G
Guy Schalnat 已提交
722

723
#ifdef PNG_SETJMP_SUPPORTED
724
   pngtest_debug("Setting jmpbuf for read struct");
725
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
726
   {
727
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
728 729
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
730
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
731
#ifdef PNG_WRITE_SUPPORTED
732
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
733
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
734
#endif
735 736
      FCLOSE(fpin);
      FCLOSE(fpout);
737
      return (1);
G
Guy Schalnat 已提交
738
   }
A
Andreas Dilger 已提交
739

740
#ifdef PNG_WRITE_SUPPORTED
741
   pngtest_debug("Setting jmpbuf for write struct");
742

743
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
744
   {
745
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
746
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
747
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
748
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
749
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
750
#endif
751 752
      FCLOSE(fpin);
      FCLOSE(fpout);
753
      return (1);
G
Guy Schalnat 已提交
754
   }
755
#endif
A
Andreas Dilger 已提交
756
#endif
757

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

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

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

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

800
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
801
   {
802
      int i;
803

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

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

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

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

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

A
Andreas Dilger 已提交
837 838 839 840
      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,
841
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
842
            color_type, interlace_type, compression_type, filter_type);
843 844 845
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
846 847
      }
   }
848 849
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
850
   {
851
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
852
         blue_y;
853

854 855
      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 已提交
856
      {
857 858
         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 已提交
859
      }
G
Guy Schalnat 已提交
860
   }
A
Andreas Dilger 已提交
861
#endif
862
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
863
   {
864
      png_fixed_point gamma;
G
Guy Schalnat 已提交
865

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

877 878 879 880 881 882 883 884
      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
885
#ifdef PNG_gAMA_SUPPORTED
886 887 888 889 890 891 892
   {
      double gamma;

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

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

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
917
#endif
918 919 920 921 922 923 924
   {
      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);
   }
925
#ifdef PNG_bKGD_SUPPORTED
926 927 928 929 930 931 932 933 934
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
935
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
936
   {
A
Andreas Dilger 已提交
937 938 939 940
      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 已提交
941
   }
A
Andreas Dilger 已提交
942
#endif
943
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
944
   {
945
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
946
      int unit_type;
G
Guy Schalnat 已提交
947

948
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
949
          &unit_type))
A
Andreas Dilger 已提交
950 951 952 953 954
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
955
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
956 957 958 959 960 961 962 963 964 965 966 967 968 969
   {
      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
970
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
971 972 973 974 975 976 977 978
   {
      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
979
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
980
   {
981
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
982

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

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

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

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

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

A
Andreas Dilger 已提交
1027 1028 1029 1030
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1031
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1032 1033 1034 1035 1036 1037
   {
      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);
1038
#ifdef PNG_TIME_RFC1123_SUPPORTED
1039 1040 1041 1042 1043
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

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

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

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

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

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

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

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

1107 1108
      unsigned char
        ster_chunk_data[1];
1109

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

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

1118 1119
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
      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]);
1130

1131 1132 1133 1134
      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);
1135 1136 1137
   }

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

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

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

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

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

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

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

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

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

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

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

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

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1219
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1220 1221 1222 1223
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1224
#ifdef PNG_tIME_SUPPORTED
1225 1226 1227 1228 1229 1230
   {
      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);
1231
#ifdef PNG_TIME_RFC1123_SUPPORTED
1232 1233 1234 1235 1236
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
            tIME_string[png_sizeof(tIME_string) - 1] = '\0';

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      if (!num_in)
         break;

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

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

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

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

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

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

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

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

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

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

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

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

   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)
   {
1435
      if (strcmp(argv[1], "-m") == 0)
1436
      {
1437
         multiple = 1;
1438 1439
         status_dots_requested = 0;
      }
1440

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1579
         kerror = test_one_file(inname, outname);
1580

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

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

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

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

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

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

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

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

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

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

1671
/* Generate a compiler error if there is an old png.h in the search path. */
1672
typedef png_libpng_version_1_6_0beta03 Your_png_h_is_not_version_1_6_0beta03;