pngtest.c 50.1 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 92 93
static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */
94

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

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

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

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

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

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

126
   status_dots--;
127

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

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

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

143
   fprintf(stdout, "w");
144 145 146
}


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

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

166
static png_uint_32 zero_samples;
167

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

175
   /* Contents of row_info:
176 177 178 179 180 181 182 183
    *  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)
    */

184
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
185

186
    if (row_info->color_type == 0 || row_info->color_type == 3)
187
    {
188
       int pos = 0;
189
       png_uint_32 n, nstop;
190

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

198
             if (pos == 8)
199
             {
200
                pos = 0;
201 202
                dp++;
             }
203
          }
204

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

210
             if (pos == 8)
211
             {
212
                pos = 0;
213 214
                dp++;
             }
215
          }
216

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

222
             if (pos == 8)
223
             {
224
                pos = 0;
225 226
                dp++;
             }
227
          }
228

229
          if (row_info->bit_depth == 8)
230 231
             if (*dp++ == 0)
                zero_samples++;
232

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

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

256
             if (row_info->bit_depth == 16)
257
             {
258 259
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
260

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

275
static int wrote_question = 0;
276

277
#ifndef PNG_STDIO_SUPPORTED
278
/* START of code to validate stdio-free compilation */
279 280 281 282 283 284 285
/* 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.
 */
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
#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

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

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

344 345
   if (check != length)
   {
346
      png_error(png_ptr, "Read Error");
347
   }
348 349 350 351

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

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

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

373
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
374

375 376 377 378
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
379 380 381 382

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
383 384 385 386 387 388 389
}

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

397 398
   ++warning_count;

399 400
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
401

402 403
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
404 405 406 407 408 409 410
}

/* 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().
 */
411
static void PNGCBAPI
412
pngtest_error(png_structp png_ptr, png_const_charp message)
413
{
414 415
   ++error_count;

416
   pngtest_warning(png_ptr, message);
417
   /* We can return because png_error calls the default handler, which is
418 419
    * actually OK in this case.
    */
420
}
421
#endif /* !PNG_STDIO_SUPPORTED */
422 423
/* END of code to validate stdio-free compilation */

424
/* START of code to validate memory allocation and deallocation */
425
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
426 427

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

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
447 448
static int total_allocation = 0;
static int num_allocations = 0;
449

450 451 452
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));
453 454

png_voidp
455
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
456
{
457

458
   /* png_malloc has already tested for NULL; png_create_struct calls
459 460
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
461

462
   if (size == 0)
463
      return (NULL);
464 465 466 467

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

478 479
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
480

481
      pinfo->pointer = png_malloc(png_ptr, size);
482
      /* Restore malloc_fn and free_fn */
483

484 485
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
486

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

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

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

504
      return (png_voidp)(pinfo->pointer);
505 506 507 508
   }
}

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

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

   /* Unlink the element from the list. */
   {
525
      memory_infop *ppinfo = &pinformation;
526

527 528
      for (;;)
      {
529
         memory_infop pinfo = *ppinfo;
530

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

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

551 552 553 554 555
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
556
   if (verbose)
557
      printf("Freeing %p\n", ptr);
558

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

565 566

/* Demonstration of user chunk support of the sTER and vpAg chunks */
567
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
568

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

static png_uint_32 user_chunk_data[4];

574 575 576 577
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
578 579
     */

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

606 607
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
608

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

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

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
/* START of code to check that libpng has the required text support; this only
 * checks for the write support because if read support is missing the chunk
 * will simply not be reported back to pngtest.
 */
#ifdef PNG_TEXT_SUPPORTED
static void
pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr,
   int num_text)
{
   while (num_text > 0)
   {
      switch (text_ptr[--num_text].compression)
      {
         case PNG_TEXT_COMPRESSION_NONE:
            break;

         case PNG_TEXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_zTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         case PNG_ITXT_COMPRESSION_NONE:
         case PNG_ITXT_COMPRESSION_zTXt:
#           ifndef PNG_WRITE_iTXt_SUPPORTED
               ++unsupported_chunks;
#           endif
            break;

         default:
            /* This is an error */
            png_error(png_ptr, "invalid text chunk compression field");
            break;
      }
   }
}
#endif
/* END of code to check that libpng has the required text support */

674
/* Test one file */
675
static int
676
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
677
{
678 679
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
680 681 682 683 684 685 686 687 688 689 690
   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 已提交
691
   png_bytep row_buf;
G
Guy Schalnat 已提交
692
   png_uint_32 y;
A
Andreas Dilger 已提交
693 694 695
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
696

697
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
698

699
   row_buf = NULL;
G
Guy Schalnat 已提交
700

A
Andreas Dilger 已提交
701
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
702 703
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
704
      return (1);
G
Guy Schalnat 已提交
705 706
   }

A
Andreas Dilger 已提交
707
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
708
   {
G
Guy Schalnat 已提交
709
      fprintf(STDERR, "Could not open output file %s\n", outname);
710
      FCLOSE(fpin);
711
      return (1);
G
Guy Schalnat 已提交
712 713
   }

714
   pngtest_debug("Allocating read and write structures");
715
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
716 717
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
718
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
719
#else
720 721
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
722
#endif
723
#ifndef PNG_STDIO_SUPPORTED
724 725
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
726
#endif
727

728
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
729 730 731 732 733 734
   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);
735

736
#endif
737
#ifdef PNG_WRITE_SUPPORTED
738
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
739 740 741
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
742
#else
743 744
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
745
#endif
746
#ifndef PNG_STDIO_SUPPORTED
747 748
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
749
#endif
750
#endif
751
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
752
   read_info_ptr = png_create_info_struct(read_ptr);
753
   end_info_ptr = png_create_info_struct(read_ptr);
754 755
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
756
   write_end_info_ptr = png_create_info_struct(write_ptr);
757
#endif
G
Guy Schalnat 已提交
758

759
#ifdef PNG_SETJMP_SUPPORTED
760
   pngtest_debug("Setting jmpbuf for read struct");
761
   if (setjmp(png_jmpbuf(read_ptr)))
G
Guy Schalnat 已提交
762
   {
763
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
764 765
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
766
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
767
#ifdef PNG_WRITE_SUPPORTED
768
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
769
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
770
#endif
771 772
      FCLOSE(fpin);
      FCLOSE(fpout);
773
      return (1);
G
Guy Schalnat 已提交
774
   }
A
Andreas Dilger 已提交
775

776
#ifdef PNG_WRITE_SUPPORTED
777
   pngtest_debug("Setting jmpbuf for write struct");
778

779
   if (setjmp(png_jmpbuf(write_ptr)))
G
Guy Schalnat 已提交
780
   {
781
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
782
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
783
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
784
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
785
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
786
#endif
787 788
      FCLOSE(fpin);
      FCLOSE(fpout);
789
      return (1);
G
Guy Schalnat 已提交
790
   }
791
#endif
A
Andreas Dilger 已提交
792
#endif
793

794 795 796 797 798 799 800 801 802 803 804
   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. */
   }

805
   pngtest_debug("Initializing input and output streams");
806
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
807
   png_init_io(read_ptr, fpin);
808
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
809
   png_init_io(write_ptr, fpout);
810
#  endif
811
#else
812
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
813
#  ifdef PNG_WRITE_SUPPORTED
814
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
815
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
816
      pngtest_flush);
817
#    else
818
      NULL);
819 820
#    endif
#  endif
821
#endif
822

823
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
824 825
   /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
    * This is here just to make pngtest replicate the results from libpng
826
    * versions prior to 1.5.4, and to test this new API.
827
    */
828 829 830
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

831
   if (status_dots_requested == 1)
832
   {
833
#ifdef PNG_WRITE_SUPPORTED
834
      png_set_write_status_fn(write_ptr, write_row_callback);
835
#endif
836 837
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
838

839 840
   else
   {
841
#ifdef PNG_WRITE_SUPPORTED
842
      png_set_write_status_fn(write_ptr, NULL);
843
#endif
844
      png_set_read_status_fn(read_ptr, NULL);
845 846
   }

847
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
848
   {
849
      int i;
850

851 852
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
853

854
      png_set_read_user_transform_fn(read_ptr, count_filters);
855 856
   }
#endif
857
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
858
   zero_samples = 0;
859 860
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
861

862
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
863 864 865
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
866 867
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
868
#endif
869
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
870 871 872
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
873 874
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
875 876
#endif

877
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
878
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
879

880
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
881 882
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
883

A
Andreas Dilger 已提交
884 885 886 887
      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,
888
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
889
            color_type, interlace_type, compression_type, filter_type);
890 891 892
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
893 894
      }
   }
895 896
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
897
   {
898
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
899
         blue_y;
900

901 902
      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 已提交
903
      {
904 905
         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 已提交
906
      }
G
Guy Schalnat 已提交
907
   }
A
Andreas Dilger 已提交
908
#endif
909
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
910
   {
911
      png_fixed_point gamma;
G
Guy Schalnat 已提交
912

913 914
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
915 916
   }
#endif
917
#else /* Use floating point versions */
918 919
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
920 921 922
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
923

924 925 926 927 928 929 930 931
      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
932
#ifdef PNG_gAMA_SUPPORTED
933 934 935 936 937 938 939
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
940 941
#endif /* Floating point */
#endif /* Fixed point */
942
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
943
   {
944
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
945
      png_bytep profile;
946
      png_uint_32 proflen;
947
      int compression_type;
A
Andreas Dilger 已提交
948

949 950
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
951
      {
952 953
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
954
      }
G
Guy Schalnat 已提交
955
   }
956
#endif
957
#ifdef PNG_sRGB_SUPPORTED
958
   {
959
      int intent;
960 961 962 963

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
964
#endif
965 966 967 968 969 970 971
   {
      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);
   }
972
#ifdef PNG_bKGD_SUPPORTED
973 974 975 976 977 978 979 980 981
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
982
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
983
   {
A
Andreas Dilger 已提交
984 985 986 987
      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 已提交
988
   }
A
Andreas Dilger 已提交
989
#endif
990
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
991
   {
992
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
993
      int unit_type;
G
Guy Schalnat 已提交
994

995
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
996
          &unit_type))
A
Andreas Dilger 已提交
997 998 999 1000 1001
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1002
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
   {
      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
1017
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1018 1019 1020 1021 1022 1023 1024 1025
   {
      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
1026
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1027
   {
1028
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1029

1030 1031
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1032
   }
1033
#endif
1034
#ifdef PNG_sCAL_SUPPORTED
1035
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
1036
   {
1037
      int unit;
1038
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1039

1040 1041
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1042
      {
1043
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1044 1045 1046
      }
   }
#else
1047
#ifdef PNG_FIXED_POINT_SUPPORTED
1048
   {
1049
      int unit;
1050
      png_charp scal_width, scal_height;
1051

1052 1053
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1054
      {
1055 1056
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1057 1058
      }
   }
G
Guy Schalnat 已提交
1059
#endif
1060 1061
#endif
#endif
1062
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1063 1064 1065 1066 1067 1068
   {
      png_textp text_ptr;
      int num_text;

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

1071 1072
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1073
         if (verbose)
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
         {
            int i;

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

A
Andreas Dilger 已提交
1085 1086 1087 1088
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1089
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1090 1091 1092 1093 1094 1095
   {
      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);
1096
#ifdef PNG_TIME_RFC1123_SUPPORTED
1097
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1098
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1099 1100

         else
1101
         {
1102 1103
            strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1104
         }
1105

1106 1107
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1108
      }
A
Andreas Dilger 已提交
1109 1110
   }
#endif
1111
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1112
   {
1113
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1114
      int num_trans;
1115
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1116

1117
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1118
         &trans_color))
A
Andreas Dilger 已提交
1119
      {
1120
         int sample_max = (1 << bit_depth);
1121
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1122
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1123
             (int)trans_color->gray > sample_max) ||
1124
             (color_type == PNG_COLOR_TYPE_RGB &&
1125 1126 1127
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1128
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1129
               trans_color);
A
Andreas Dilger 已提交
1130 1131 1132
      }
   }
#endif
1133
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1134 1135
   {
      png_unknown_chunkp unknowns;
1136
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1137
         &unknowns);
1138

1139 1140
      if (num_unknowns)
      {
1141
         int i;
1142 1143
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1144
         /* Copy the locations from the read_info_ptr.  The automatically
1145 1146 1147
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1148
         for (i = 0; i < num_unknowns; i++)
1149 1150
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1151 1152 1153
      }
   }
#endif
A
Andreas Dilger 已提交
1154

1155
#ifdef PNG_WRITE_SUPPORTED
1156
   pngtest_debug("Writing info struct");
1157 1158

/* If we wanted, we could write info in two steps:
1159
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1160
 */
A
Andreas Dilger 已提交
1161
   png_write_info(write_ptr, write_info_ptr);
1162

1163
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1164 1165
   if (user_chunk_data[0] != 0)
   {
1166
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1167

1168 1169
      unsigned char
        ster_chunk_data[1];
1170

1171 1172 1173
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1174

1175 1176
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1177
   }
1178

1179 1180
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
      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]);
1191

1192 1193 1194 1195
      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);
1196 1197 1198
   }

#endif
1199
#endif
A
Andreas Dilger 已提交
1200

1201
#ifdef SINGLE_ROWBUF_ALLOC
1202
   pngtest_debug("Allocating row buffer...");
1203
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1204
      png_get_rowbytes(read_ptr, read_info_ptr));
1205

1206
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1207
#endif /* SINGLE_ROWBUF_ALLOC */
1208
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1209

1210 1211
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1212
   num_pass = png_set_interlace_handling(read_ptr);
1213
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1214
   png_set_interlace_handling(write_ptr);
1215
#  endif
1216
#else
1217
   num_pass = 1;
1218
#endif
A
Andreas Dilger 已提交
1219

1220 1221 1222 1223 1224
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1225 1226
   for (pass = 0; pass < num_pass; pass++)
   {
1227
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1228 1229
      for (y = 0; y < height; y++)
      {
1230
#ifndef SINGLE_ROWBUF_ALLOC
1231
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1232 1233
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1234

1235
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1236
            png_get_rowbytes(read_ptr, read_info_ptr));
1237

1238
#endif /* !SINGLE_ROWBUF_ALLOC */
1239
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1240 1241

#ifdef PNG_WRITE_SUPPORTED
1242 1243 1244 1245 1246
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1247
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1248 1249 1250 1251 1252
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1253 1254 1255
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1256
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1257
         png_free(read_ptr, row_buf);
1258
         row_buf = NULL;
1259
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1260 1261 1262
      }
   }

1263
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1264
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1265
#endif
1266
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1267
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1268 1269
#endif

1270
   pngtest_debug("Reading and writing end_info data");
1271

A
Andreas Dilger 已提交
1272
   png_read_end(read_ptr, end_info_ptr);
1273
#ifdef PNG_TEXT_SUPPORTED
1274 1275 1276 1277 1278 1279
   {
      png_textp text_ptr;
      int num_text;

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

1282 1283
         pngtest_check_text_support(read_ptr, text_ptr, num_text);

1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
         if (verbose)
         {
            int i;

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

1296 1297 1298 1299
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1300
#ifdef PNG_tIME_SUPPORTED
1301 1302 1303 1304 1305 1306
   {
      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);
1307
#ifdef PNG_TIME_RFC1123_SUPPORTED
1308
         if (png_convert_to_rfc1123_buffer(tIME_string, mod_time))
1309
            tIME_string[(sizeof tIME_string) - 1] = '\0';
1310 1311

         else
1312 1313 1314 1315
         {
            strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
            tIME_string[(sizeof tIME_string)-1] = '\0';
         }
1316

1317 1318 1319 1320
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1321
#endif
1322
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1323 1324
   {
      png_unknown_chunkp unknowns;
1325
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1326
         &unknowns);
1327

1328 1329
      if (num_unknowns)
      {
1330
         int i;
1331 1332
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1333
         /* Copy the locations from the read_info_ptr.  The automatically
1334 1335 1336
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1337
         for (i = 0; i < num_unknowns; i++)
1338 1339
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1340 1341
      }
   }
1342
#endif
1343
#ifdef PNG_WRITE_SUPPORTED
1344
   png_write_end(write_ptr, write_end_info_ptr);
1345
#endif
1346

1347
#ifdef PNG_EASY_ACCESS_SUPPORTED
1348
   if (verbose)
1349 1350 1351 1352
   {
      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);
1353
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1354
         (unsigned long)iwidth, (unsigned long)iheight);
1355 1356
   }
#endif
G
Guy Schalnat 已提交
1357

1358
   pngtest_debug("Destroying data structs");
1359
#ifdef SINGLE_ROWBUF_ALLOC
1360
   pngtest_debug("destroying row_buf for read_ptr");
1361
   png_free(read_ptr, row_buf);
1362
   row_buf = NULL;
1363
#endif /* SINGLE_ROWBUF_ALLOC */
1364
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1365
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1366
#ifdef PNG_WRITE_SUPPORTED
1367
   pngtest_debug("destroying write_end_info_ptr");
1368
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1369
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1370
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1371
#endif
1372
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1373

1374 1375
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1376

1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
   /* Summarize any warnings or errors and in 'strict' mode fail the test.
    * Unsupported chunks can result in warnings, in that case ignore the strict
    * setting, otherwise fail the test on warnings as well as errors.
    */
   if (error_count > 0)
   {
      /* We don't really expect to get here because of the setjmp handling
       * above, but this is safe.
       */
      fprintf(STDERR, "%s: %d libpng errors found (%d warnings)\n",
         inname, error_count, warning_count);

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

   else if (unsupported_chunks > 0)
   {
      fprintf(STDERR, "%s: unsupported chunks (%d)%s\n",
         inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
   }

   else if (warning_count > 0)
   {
      fprintf(STDERR, "%s: %d libpng warnings found\n",
         inname, warning_count);

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

1408
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1409
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1410
   {
G
Guy Schalnat 已提交
1411
      fprintf(STDERR, "Could not find file %s\n", inname);
1412
      return (1);
G
Guy Schalnat 已提交
1413 1414
   }

A
Andreas Dilger 已提交
1415
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1416
   {
G
Guy Schalnat 已提交
1417
      fprintf(STDERR, "Could not find file %s\n", outname);
1418
      FCLOSE(fpin);
1419
      return (1);
G
Guy Schalnat 已提交
1420
   }
A
Andreas Dilger 已提交
1421

1422
   for (;;)
G
Guy Schalnat 已提交
1423
   {
A
Andreas Dilger 已提交
1424
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1425

1426 1427
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1428 1429 1430

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

1434
         if (wrote_question == 0 && unsupported_chunks == 0)
1435 1436
         {
            fprintf(STDERR,
1437
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1438
              inname, PNG_ZBUF_SIZE);
1439
            fprintf(STDERR,
1440
              "\n   filtering heuristic (libpng default), compression");
1441
            fprintf(STDERR,
1442
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1443
              ZLIB_VERSION);
1444
            wrote_question = 1;
1445
         }
1446

1447 1448
         FCLOSE(fpin);
         FCLOSE(fpout);
1449

1450
         if (strict != 0 && unsupported_chunks == 0)
1451 1452 1453 1454
           return (1);

         else
           return (0);
G
Guy Schalnat 已提交
1455 1456 1457 1458 1459
      }

      if (!num_in)
         break;

1460
      if (memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1461
      {
1462
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1463

1464
         if (wrote_question == 0 && unsupported_chunks == 0)
1465 1466
         {
            fprintf(STDERR,
1467
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1468
                 inname, PNG_ZBUF_SIZE);
1469
            fprintf(STDERR,
1470
              "\n   filtering heuristic (libpng default), compression");
1471
            fprintf(STDERR,
1472
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1473
              ZLIB_VERSION);
1474
            wrote_question = 1;
1475
         }
1476

1477 1478
         FCLOSE(fpin);
         FCLOSE(fpout);
1479

1480 1481 1482 1483 1484 1485
         /* NOTE: the unsupported_chunks escape is permitted here because
          * unsupported text chunk compression will result in the compression
          * mode being changed (to NONE) yet, in the test case, the result can
          * be exactly the same size!
          */
         if (strict != 0 && unsupported_chunks == 0)
1486 1487 1488 1489
           return (1);

         else
           return (0);
G
Guy Schalnat 已提交
1490 1491 1492
      }
   }

1493 1494
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1495

1496
   return (0);
G
Guy Schalnat 已提交
1497
}
G
Guy Schalnat 已提交
1498

1499
/* Input and output filenames */
1500
#ifdef RISCOS
1501 1502
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1503
#else
1504 1505
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1506 1507 1508 1509 1510 1511 1512 1513
#endif

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

1514
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1515
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1516
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1517
   /* Show the version of libpng used in building the library */
1518 1519
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1520
      png_get_header_version(NULL));
1521

1522
   /* Show the version of libpng used in building the application */
1523
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1524
      PNG_HEADER_VERSION_STRING);
1525 1526

   /* Do some consistency checking on the memory allocation settings, I'm
1527 1528 1529 1530
    * 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
    */
1531
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1532
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1533
#endif
1534
   /* I think the following can happen. */
1535
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1536
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1537
#endif
1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549

   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)
   {
1550
      if (strcmp(argv[1], "-m") == 0)
1551
      {
1552
         multiple = 1;
1553 1554
         status_dots_requested = 0;
      }
1555

1556 1557 1558 1559 1560
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1561
         status_dots_requested = 1;
1562
      }
1563

1564 1565 1566
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1567
         status_dots_requested = 1;
1568 1569
         inname = argv[2];
      }
1570

1571 1572 1573 1574 1575 1576 1577 1578
      else if (strcmp(argv[1], "--strict") == 0)
      {
         status_dots_requested = 0;
         verbose = 1;
         inname = argv[2];
         strict++;
      }

1579
      else
1580
      {
1581
         inname = argv[1];
1582 1583
         status_dots_requested = 0;
      }
1584 1585
   }

1586 1587
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1588

1589
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1590
   {
1591 1592
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1593
        argv[0], argv[0]);
1594 1595 1596 1597
     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);
1598 1599 1600 1601 1602 1603
     exit(1);
   }

   if (multiple)
   {
      int i;
1604
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1605 1606
      int allocation_now = current_allocation;
#endif
1607
      for (i=2; i<argc; ++i)
1608
      {
1609
         int kerror;
1610
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1611
         kerror = test_one_file(argv[i], outname);
1612
         if (kerror == 0)
1613
         {
1614 1615 1616
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1617
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1618
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1619
               (unsigned long)zero_samples);
1620
#else
1621
            fprintf(STDERR, " PASS\n");
1622
#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 1634 1635
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1636

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

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

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

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

1676 1677
   else
   {
1678
      int i;
1679
      for (i = 0; i<3; ++i)
1680
      {
1681
         int kerror;
1682
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1683 1684
         int allocation_now = current_allocation;
#endif
1685 1686 1687 1688 1689 1690
         if (i == 1)
            status_dots_requested = 1;

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

1691
         if (i == 0 || verbose == 1 || ierror != 0)
1692
            fprintf(STDERR, "\n Testing %s:", inname);
1693

1694
         kerror = test_one_file(inname, outname);
1695

1696
         if (kerror == 0)
1697
         {
1698
            if (verbose == 1 || i == 2)
1699
            {
1700
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1701
                int k;
1702
#endif
1703
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1704
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1705
                   (unsigned long)zero_samples);
1706 1707 1708
#else
                fprintf(STDERR, " PASS\n");
#endif
1709
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1710 1711
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1712
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1713
                         k, (unsigned long)filters_used[k]);
1714
#endif
1715
#ifdef PNG_TIME_RFC1123_SUPPORTED
1716 1717
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1718 1719
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1720
         }
1721

1722 1723
         else
         {
1724
            if (verbose == 0 && i != 2)
1725
               fprintf(STDERR, "\n Testing %s:", inname);
1726

1727 1728
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1729
         }
1730
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1731 1732
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1733
               current_allocation - allocation_now);
1734

1735 1736
         if (current_allocation != 0)
         {
1737
             memory_infop pinfo = pinformation;
1738

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

1742 1743
             while (pinfo != NULL)
             {
1744 1745
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1746 1747 1748 1749
                pinfo = pinfo->next;
             }
          }
#endif
1750
       }
1751
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1752
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1753
          current_allocation);
1754
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1755
          maximum_allocation);
1756 1757 1758 1759
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1760
#endif
1761 1762
   }

1763 1764 1765 1766
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1767
   fprintf(STDERR, " CPU time used = %.3f seconds",
1768
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1769
   fprintf(STDERR, " (decoding %.3f,\n",
1770
      t_decode/(float)CLOCKS_PER_SEC);
1771
   fprintf(STDERR, "        encoding %.3f ,",
1772
      t_encode/(float)CLOCKS_PER_SEC);
1773
   fprintf(STDERR, " other %.3f seconds)\n\n",
1774 1775 1776
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1777
   if (ierror == 0)
1778
      fprintf(STDERR, " libpng passes test\n");
1779

1780
   else
1781
      fprintf(STDERR, " libpng FAILS test\n");
1782

1783
   return (int)(ierror != 0);
1784
}
1785

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