pngtest.c 47.6 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.0 [February 19, 2010]
5
 * Copyright (c) 1998-2010 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
#include "png.h"
35
#include "pngpriv.h"
36

37 38 39
#  include <stdio.h>
#  include <stdlib.h>
#  define FCLOSE(file) fclose(file)
40

41
#ifndef PNG_STDIO_SUPPORTED
42
     typedef FILE                * png_FILE_p;
43 44
#endif

A
Andreas Dilger 已提交
45 46
/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
#ifndef PNG_DEBUG
47 48 49 50
#  define PNG_DEBUG 0
#endif

#if !PNG_DEBUG
51
#  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
52
#endif
A
Andreas Dilger 已提交
53

54 55 56 57
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

58
#ifndef PNG_FLOATING_POINT_SUPPORTED
59 60 61
#undef PNGTEST_TIMING
#endif

62 63 64 65 66
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

67
#ifdef PNG_TIME_RFC1123_SUPPORTED
68
#define PNG_tIME_STRING_LENGTH 29
69
static int tIME_chunk_present = 0;
70
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
71 72
#endif

73 74
static int verbose = 0;

75
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
76

G
Guy Schalnat 已提交
77 78 79 80
#ifdef __TURBOC__
#include <mem.h>
#endif

81
/* Defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
82
/*  #define STDERR stderr  */
83
#define STDERR stdout   /* For DOS */
G
Guy Schalnat 已提交
84

85 86 87 88 89 90 91 92 93 94
/* In case a system header (e.g., on AIX) defined jmpbuf */
#ifdef jmpbuf
#  undef jmpbuf
#endif

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

95
/* Example of using row callbacks to make a simple progress meter */
96 97 98
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
99

100 101
void
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
102
void
103
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
104
{
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
   status_dots--;
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
   fprintf(stdout, "r");
120
}
121

122
void
123
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
124
void
125
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
126
{
127 128 129
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
   fprintf(stdout, "w");
130 131 132
}


133
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
134
/* Example of using user transform callback (we don't transform anything,
135 136 137
 * but merely examine the row filters.  We set this to 256 rather than
 * 5 in case illegal filter values are present.)
 */
138 139
static png_uint_32 filters_used[256];
void
140 141
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
void
142 143
count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
{
144
   if (png_ptr != NULL && row_info != NULL)
145
      ++filters_used[*(data - 1)];
146 147 148
}
#endif

149
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
150
/* Example of using user transform callback (we don't transform anything,
151 152
 * but merely count the zero samples)
 */
153

154
static png_uint_32 zero_samples;
155

156 157
void
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
158
void
159
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
160 161
{
   png_bytep dp = data;
162
   if (png_ptr == NULL)return;
163

164
   /* Contents of row_info:
165 166 167 168 169 170 171 172
    *  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)
    */

173
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
174

175
    if (row_info->color_type == 0 || row_info->color_type == 3)
176
    {
177
       int pos = 0;
178
       png_uint_32 n, nstop;
179
       for (n = 0, nstop=row_info->width; n<nstop; n++)
180
       {
181
          if (row_info->bit_depth == 1)
182
          {
183 184
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
185
             if (pos == 8)
186
             {
187
                pos = 0;
188 189
                dp++;
             }
190
          }
191
          if (row_info->bit_depth == 2)
192
          {
193 194
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
195
             if (pos == 8)
196
             {
197
                pos = 0;
198 199
                dp++;
             }
200
          }
201
          if (row_info->bit_depth == 4)
202
          {
203 204
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
205
             if (pos == 8)
206
             {
207
                pos = 0;
208 209
                dp++;
             }
210
          }
211
          if (row_info->bit_depth == 8)
212 213
             if (*dp++ == 0)
                zero_samples++;
214
          if (row_info->bit_depth == 16)
215
          {
216 217
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
218 219 220 221
             dp+=2;
          }
       }
    }
222
    else /* Other color types */
223
    {
224
       png_uint_32 n, nstop;
225 226
       int channel;
       int color_channels = row_info->channels;
227
       if (row_info->color_type > 3)color_channels--;
228

229
       for (n = 0, nstop=row_info->width; n<nstop; n++)
230 231 232
       {
          for (channel = 0; channel < color_channels; channel++)
          {
233
             if (row_info->bit_depth == 8)
234 235
                if (*dp++ == 0)
                   zero_samples++;
236
             if (row_info->bit_depth == 16)
237
             {
238 239
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
240 241 242
                dp+=2;
             }
          }
243
          if (row_info->color_type > 3)
244 245
          {
             dp++;
246 247
             if (row_info->bit_depth == 16)
                dp++;
248 249 250 251
          }
       }
    }
}
252
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
253

254
static int wrote_question = 0;
255

256
#ifndef PNG_STDIO_SUPPORTED
257
/* START of code to validate stdio-free compilation */
258 259 260 261 262 263 264
/* 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.
 */
265

266 267
#ifndef USE_FAR_KEYWORD
static void
268
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
269
{
270 271
   png_size_t check = 0;
   png_voidp io_ptr;
272 273 274 275

   /* 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.
    */
276 277 278 279 280
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
281

282 283
   if (check != length)
   {
284
      png_error(png_ptr, "Read Error!");
285 286
   }
}
G
Guy Schalnat 已提交
287
#else
288
/* This is the model-independent version. Since the standard I/O library
289 290 291
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
292

293 294
#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)
295

296
static void
297
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
298
{
299
   png_size_t check;
300
   png_byte *n_data;
301
   png_FILE_p io_ptr;
302 303 304

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
305
   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
306 307
   if ((png_bytep)n_data == data)
   {
308
      check = fread(n_data, 1, length, io_ptr);
309 310 311 312 313 314 315 316 317 318
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
319
         err = fread(buf, 1, 1, io_ptr);
320
         png_memcpy(data, buf, read); /* Copy far buffer to near buffer */
321
         if (err != read)
322 323 324 325 326 327 328 329 330 331 332
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
   if (check != length)
      png_error(png_ptr, "read Error");
}
333
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
334

335
#ifdef PNG_WRITE_FLUSH_SUPPORTED
336
static void
337
pngtest_flush(png_structp png_ptr)
338
{
339
   /* Do nothing; fflush() is said to be just a waste of energy. */
340
   png_ptr = png_ptr;  /* Stifle compiler warning */
341 342
}
#endif
G
Guy Schalnat 已提交
343

344
/* This is the function that does the actual writing of data.  If you are
345 346 347 348
 * 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.
 */
349 350
#ifndef USE_FAR_KEYWORD
static void
351
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
352
{
353
   png_size_t check;
354

355
   check = fwrite(data, 1, length, (png_FILE_p)png_ptr->io_ptr);
356 357 358 359 360 361
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
#else
362
/* This is the model-independent version. Since the standard I/O library
363 364 365 366 367 368 369 370
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/

#define NEAR_BUF_SIZE 1024
#define MIN(a,b) (a <= b ? a : b)

static void
371
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
372
{
373
   png_size_t check;
374
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
375
   png_FILE_p io_ptr;
376 377 378

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
379
   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
380 381
   if ((png_bytep)near_data == data)
   {
382
      check = fwrite(near_data, 1, length, io_ptr);
383 384 385 386 387 388 389 390 391 392
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
393
         png_memcpy(buf, data, written); /* Copy far buffer to near buffer */
394
         err = fwrite(buf, 1, written, io_ptr);
395 396 397 398 399 400 401 402 403 404 405 406 407 408
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
409
#endif /* USE_FAR_KEYWORD */
410 411 412 413 414 415 416

/* 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.
 */
static void
417
pngtest_warning(png_structp png_ptr, png_const_charp message)
418 419
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
420 421 422 423 424 425
   char *test;
   test = png_get_error_ptr(png_ptr);
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
426 427 428 429 430 431 432 433
}

/* 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().
 */
static void
434
pngtest_error(png_structp png_ptr, png_const_charp message)
435
{
436
   pngtest_warning(png_ptr, message);
437
   /* We can return because png_error calls the default handler, which is
438 439
    * actually OK in this case.
    */
440
}
441
#endif /* !PNG_STDIO_SUPPORTED */
442 443
/* END of code to validate stdio-free compilation */

444
/* START of code to validate memory allocation and deallocation */
445
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
446 447

/* Allocate memory.  For reasonable files, size should never exceed
448 449 450 451 452 453 454 455
 * 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.
 */
456 457
typedef struct memory_information
{
458
   png_alloc_size_t          size;
459
   png_voidp                 pointer;
460 461 462 463 464 465 466
   struct memory_information FAR *next;
} memory_information;
typedef memory_information FAR *memory_infop;

static memory_infop pinformation = NULL;
static int current_allocation = 0;
static int maximum_allocation = 0;
467 468
static int total_allocation = 0;
static int num_allocations = 0;
469

470 471
png_voidp png_debug_malloc
   PNGARG((png_structp png_ptr, png_alloc_size_t size));
472
void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
473 474

png_voidp
475
png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
476
{
477

478
   /* png_malloc has already tested for NULL; png_create_struct calls
479 480
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
481

482
   if (size == 0)
483
      return (NULL);
484 485 486 487

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
488
      /* Disable malloc_fn and free_fn */
489
      memory_infop pinfo;
490
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
491 492
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
493 494
      pinfo->size = size;
      current_allocation += size;
495 496
      total_allocation += size;
      num_allocations ++;
497 498
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
499
      pinfo->pointer = png_malloc(png_ptr, size);
500
      /* Restore malloc_fn and free_fn */
501 502
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
503 504 505 506
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
507
         png_error(png_ptr,
508
           "out of memory in pngtest->png_debug_malloc");
509
      }
510 511 512 513
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
514 515
      if (verbose)
         printf("png_malloc %lu bytes at %x\n", (unsigned long)size,
516
            pinfo->pointer);
517
      return (png_voidp)(pinfo->pointer);
518 519 520 521 522
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
void
523
png_debug_free(png_structp png_ptr, png_voidp ptr)
524 525
{
   if (png_ptr == NULL)
526
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
527 528
   if (ptr == 0)
   {
529 530 531 532 533 534 535 536 537
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
      memory_infop FAR *ppinfo = &pinformation;
538 539
      for (;;)
      {
540
         memory_infop pinfo = *ppinfo;
541 542
         if (pinfo->pointer == ptr)
         {
543 544 545 546 547
            *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
548
               the memory that is to be freed. */
549
            png_memset(ptr, 0x55, pinfo->size);
550
            png_free_default(png_ptr, pinfo);
551
            pinfo = NULL;
552 553
            break;
         }
554 555
         if (pinfo->next == NULL)
         {
556
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
557 558 559 560 561 562 563
            break;
         }
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
564 565
   if (verbose)
      printf("Freeing %x\n", ptr);
566
   png_free_default(png_ptr, ptr);
567
   ptr = NULL;
568
}
569
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
570 571
/* END of code to test memory allocation/deallocation */

572 573

/* Demonstration of user chunk support of the sTER and vpAg chunks */
574
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
575

576
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
577 578 579 580
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

581 582 583 584
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
585 586 587 588 589
     */

static int read_user_chunk_callback(png_struct *png_ptr,
   png_unknown_chunkp chunk)
{
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
   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 */
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
         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);
635 636 637 638 639

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

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

668
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
669

670
   row_buf = NULL;
G
Guy Schalnat 已提交
671

A
Andreas Dilger 已提交
672
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
673 674
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
675
      return (1);
G
Guy Schalnat 已提交
676 677
   }

A
Andreas Dilger 已提交
678
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
679
   {
G
Guy Schalnat 已提交
680
      fprintf(STDERR, "Could not open output file %s\n", outname);
681
      FCLOSE(fpin);
682
      return (1);
G
Guy Schalnat 已提交
683 684
   }

685
   png_debug(0, "Allocating read and write structures");
686
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
687 688 689 690
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL,
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
691
#else
692 693
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
694
#endif
695
#ifndef PNG_STDIO_SUPPORTED
696 697
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
698
#endif
699

700
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
701 702 703 704 705 706
   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);
707

708
#endif
709
#ifdef PNG_WRITE_SUPPORTED
710
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
711 712 713
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
714
#else
715 716
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
717
#endif
718
#ifndef PNG_STDIO_SUPPORTED
719 720
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
721
#endif
722
#endif
723
   png_debug(0, "Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
724
   read_info_ptr = png_create_info_struct(read_ptr);
725
   end_info_ptr = png_create_info_struct(read_ptr);
726 727
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
728
   write_end_info_ptr = png_create_info_struct(write_ptr);
729
#endif
G
Guy Schalnat 已提交
730

731
#ifdef PNG_SETJMP_SUPPORTED
732
   png_debug(0, "Setting jmpbuf for read struct");
A
Andreas Dilger 已提交
733
#ifdef USE_FAR_KEYWORD
734
   if (setjmp(jmpbuf))
A
Andreas Dilger 已提交
735
#else
736
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
737
#endif
G
Guy Schalnat 已提交
738
   {
739
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
740 741
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
742
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
743
#ifdef PNG_WRITE_SUPPORTED
744
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
745
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
746
#endif
747 748
      FCLOSE(fpin);
      FCLOSE(fpout);
749
      return (1);
G
Guy Schalnat 已提交
750
   }
751
#ifdef USE_FAR_KEYWORD
752
   png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf));
753
#endif
A
Andreas Dilger 已提交
754

755
#ifdef PNG_WRITE_SUPPORTED
756
   png_debug(0, "Setting jmpbuf for write struct");
A
Andreas Dilger 已提交
757
#ifdef USE_FAR_KEYWORD
758
   if (setjmp(jmpbuf))
A
Andreas Dilger 已提交
759
#else
760
   if (setjmp(png_jmpbuf(write_ptr)))
A
Andreas Dilger 已提交
761
#endif
G
Guy Schalnat 已提交
762
   {
763
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
764
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
765
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
766
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
767
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
768
#endif
769 770
      FCLOSE(fpin);
      FCLOSE(fpout);
771
      return (1);
G
Guy Schalnat 已提交
772
   }
A
Andreas Dilger 已提交
773
#ifdef USE_FAR_KEYWORD
774
   png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf));
775
#endif
776
#endif
A
Andreas Dilger 已提交
777
#endif
778

779
   png_debug(0, "Initializing input and output streams");
780
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
781
   png_init_io(read_ptr, fpin);
782
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
783
   png_init_io(write_ptr, fpout);
784
#  endif
785
#else
786
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
787
#  ifdef PNG_WRITE_SUPPORTED
788
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
789
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
790
      pngtest_flush);
791
#    else
792
      NULL);
793 794
#    endif
#  endif
795
#endif
796
   if (status_dots_requested == 1)
797
   {
798
#ifdef PNG_WRITE_SUPPORTED
799
      png_set_write_status_fn(write_ptr, write_row_callback);
800
#endif
801 802 803 804
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
   else
   {
805
#ifdef PNG_WRITE_SUPPORTED
806
      png_set_write_status_fn(write_ptr, NULL);
807
#endif
808
      png_set_read_status_fn(read_ptr, NULL);
809 810
   }

811
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
812
   {
813 814 815 816
      int i;
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
      png_set_read_user_transform_fn(read_ptr, count_filters);
817 818
   }
#endif
819
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
820
   zero_samples = 0;
821 822
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
823

824
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
825 826 827
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
828 829
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
830
#endif
831
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
832 833 834
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
835 836
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
837 838
#endif

839
   png_debug(0, "Reading info struct");
A
Andreas Dilger 已提交
840
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
841

842
   png_debug(0, "Transferring info struct");
A
Andreas Dilger 已提交
843 844
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
845

A
Andreas Dilger 已提交
846 847 848 849
      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,
850
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
851
            color_type, interlace_type, compression_type, filter_type);
852 853 854
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
855 856
      }
   }
857 858
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
859
   {
860
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
861
         blue_y;
862 863
      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 已提交
864
      {
865 866
         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 已提交
867
      }
G
Guy Schalnat 已提交
868
   }
A
Andreas Dilger 已提交
869
#endif
870
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
871
   {
872
      png_fixed_point gamma;
G
Guy Schalnat 已提交
873

874 875
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
876 877
   }
#endif
878
#else /* Use floating point versions */
879 880
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
881 882 883 884 885 886 887 888 889 890 891
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
      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
892
#ifdef PNG_gAMA_SUPPORTED
893 894 895 896 897 898 899
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
900 901
#endif /* Floating point */
#endif /* Fixed point */
902
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
903
   {
904 905
      png_charp name;
      png_charp profile;
906
      png_uint_32 proflen;
907
      int compression_type;
A
Andreas Dilger 已提交
908

909 910
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
911
      {
912 913
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
914
      }
G
Guy Schalnat 已提交
915
   }
916
#endif
917
#ifdef PNG_sRGB_SUPPORTED
918
   {
919
      int intent;
920 921 922 923

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
924
#endif
925 926 927 928 929 930 931
   {
      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);
   }
932
#ifdef PNG_bKGD_SUPPORTED
933 934 935 936 937 938 939 940 941
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
942
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
943
   {
A
Andreas Dilger 已提交
944 945 946 947
      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 已提交
948
   }
A
Andreas Dilger 已提交
949
#endif
950
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
951
   {
952
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
953
      int unit_type;
G
Guy Schalnat 已提交
954

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

990 991
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
992
   }
993
#endif
994
#ifdef PNG_sCAL_SUPPORTED
995
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
996
   {
997
      int unit;
998
      double scal_width, scal_height;
A
Andreas Dilger 已提交
999

1000 1001
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1002
      {
1003
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1004 1005 1006
      }
   }
#else
1007
#ifdef PNG_FIXED_POINT_SUPPORTED
1008
   {
1009
      int unit;
1010
      png_charp scal_width, scal_height;
1011

1012 1013
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1014
      {
1015 1016
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1017 1018
      }
   }
G
Guy Schalnat 已提交
1019
#endif
1020 1021
#endif
#endif
1022
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1023 1024 1025 1026 1027 1028
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1029
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
A
Andreas Dilger 已提交
1030 1031 1032 1033
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1034
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1035 1036 1037 1038 1039 1040
   {
      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);
1041
#ifdef PNG_TIME_RFC1123_SUPPORTED
1042
         /* We have to use png_memcpy instead of "=" because the string
1043 1044 1045
          * pointed to by png_convert_to_rfc1123() gets free'ed before
          * we use it.
          */
1046 1047 1048 1049
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1050 1051
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1052
      }
A
Andreas Dilger 已提交
1053 1054
   }
#endif
1055
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1056
   {
1057
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1058
      int num_trans;
1059
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1060

1061
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1062
         &trans_color))
A
Andreas Dilger 已提交
1063
      {
1064
         int sample_max = (1 << bit_depth);
1065
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1066
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1067
             (int)trans_color->gray > sample_max) ||
1068
             (color_type == PNG_COLOR_TYPE_RGB &&
1069 1070 1071
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1072
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1073
               trans_color);
A
Andreas Dilger 已提交
1074 1075 1076
      }
   }
#endif
1077
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1078 1079 1080 1081 1082 1083 1084 1085 1086
   {
      png_unknown_chunkp unknowns;
      int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
         &unknowns);
      if (num_unknowns)
      {
         png_size_t i;
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1087
         /* Copy the locations from the read_info_ptr.  The automatically
1088 1089 1090
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1091
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1092 1093
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1094 1095 1096
      }
   }
#endif
A
Andreas Dilger 已提交
1097

1098
#ifdef PNG_WRITE_SUPPORTED
1099
   png_debug(0, "Writing info struct");
1100 1101

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

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

1111 1112
      unsigned char
        ster_chunk_data[1];
1113

1114 1115 1116 1117 1118
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1119 1120 1121
   }
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
      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]);
      png_save_uint_32(vpag_chunk_data, user_chunk_data[1]);
      png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]);
      vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff);
      png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9);
1136 1137 1138
   }

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

1141
#ifdef SINGLE_ROWBUF_ALLOC
1142
   png_debug(0, "Allocating row buffer...");
1143
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1144
      png_get_rowbytes(read_ptr, read_info_ptr));
1145
   png_debug1(0, "0x%08lx", (unsigned long)row_buf);
1146
#endif /* SINGLE_ROWBUF_ALLOC */
1147
   png_debug(0, "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
      png_debug1(0, "Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1167 1168
      for (y = 0; y < height; y++)
      {
1169
#ifndef SINGLE_ROWBUF_ALLOC
1170
         png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y);
1171 1172
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1173
         png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf,
1174 1175
            png_get_rowbytes(read_ptr, read_info_ptr));
#endif /* !SINGLE_ROWBUF_ALLOC */
1176
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1177 1178

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

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

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

1207
   png_debug(0, "Reading and writing end_info data");
1208

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

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1217
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text);
1218 1219 1220 1221
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1222
#ifdef PNG_tIME_SUPPORTED
1223 1224 1225 1226 1227 1228
   {
      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);
1229
#ifdef PNG_TIME_RFC1123_SUPPORTED
1230
         /* We have to use png_memcpy instead of "=" because the string
1231 1232
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1233 1234 1235 1236
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1237 1238 1239 1240
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1241
#endif
1242
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252
   {
      png_unknown_chunkp unknowns;
      int num_unknowns;
      num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
         &unknowns);
      if (num_unknowns)
      {
         png_size_t i;
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1253
         /* Copy the locations from the read_info_ptr.  The automatically
1254 1255 1256
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1257
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1258 1259
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1260 1261
      }
   }
1262
#endif
1263
#ifdef PNG_WRITE_SUPPORTED
1264
   png_write_end(write_ptr, write_end_info_ptr);
1265
#endif
1266

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

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

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

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

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

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

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

      if (num_in != num_out)
      {
1320
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1321
                 inname, outname);
1322
         if (wrote_question == 0)
1323 1324
         {
            fprintf(STDERR,
1325
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1326
              inname, PNG_ZBUF_SIZE);
1327
            fprintf(STDERR,
1328
              "\n   filtering heuristic (libpng default), compression");
1329
            fprintf(STDERR,
1330
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1331
              ZLIB_VERSION);
1332
            wrote_question = 1;
1333
         }
1334 1335
         FCLOSE(fpin);
         FCLOSE(fpout);
1336
         return (0);
G
Guy Schalnat 已提交
1337 1338 1339 1340 1341
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1342
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1343
      {
1344
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1345
         if (wrote_question == 0)
1346 1347
         {
            fprintf(STDERR,
1348
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1349
                 inname, PNG_ZBUF_SIZE);
1350
            fprintf(STDERR,
1351
              "\n   filtering heuristic (libpng default), compression");
1352
            fprintf(STDERR,
1353
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1354
              ZLIB_VERSION);
1355
            wrote_question = 1;
1356
         }
1357 1358
         FCLOSE(fpin);
         FCLOSE(fpout);
1359
         return (0);
G
Guy Schalnat 已提交
1360 1361 1362
      }
   }

1363 1364
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1365

1366
   return (0);
G
Guy Schalnat 已提交
1367
}
G
Guy Schalnat 已提交
1368

1369
/* Input and output filenames */
1370
#ifdef RISCOS
1371 1372
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1373
#else
1374 1375
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1376 1377 1378 1379 1380 1381 1382 1383
#endif

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

1384
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1385
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1386
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1387
   /* Show the version of libpng used in building the library */
1388 1389
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1390
      png_get_header_version(NULL));
1391
   /* Show the version of libpng used in building the application */
1392
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1393
      PNG_HEADER_VERSION_STRING);
1394 1395

   /* Do some consistency checking on the memory allocation settings, I'm
1396 1397 1398 1399
    * 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
    */
1400
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1401
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1402
#endif
1403
   /* I think the following can happen. */
1404
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1405
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1406
#endif
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418

   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)
   {
1419
      if (strcmp(argv[1], "-m") == 0)
1420
      {
1421
         multiple = 1;
1422 1423
         status_dots_requested = 0;
      }
1424 1425 1426 1427 1428
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1429
         status_dots_requested = 1;
1430 1431 1432 1433
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1434
         status_dots_requested = 1;
1435 1436 1437
         inname = argv[2];
      }
      else
1438
      {
1439
         inname = argv[1];
1440 1441
         status_dots_requested = 0;
      }
1442 1443
   }

1444 1445
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1446

1447
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1448
   {
1449 1450
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1451
        argv[0], argv[0]);
1452 1453 1454 1455
     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);
1456 1457 1458 1459 1460 1461
     exit(1);
   }

   if (multiple)
   {
      int i;
1462
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1463 1464
      int allocation_now = current_allocation;
#endif
1465
      for (i=2; i<argc; ++i)
1466
      {
1467
         int kerror;
1468
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1469
         kerror = test_one_file(argv[i], outname);
1470
         if (kerror == 0)
1471
         {
1472 1473 1474
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1475
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1476
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1477
               (unsigned long)zero_samples);
1478
#else
1479
            fprintf(STDERR, " PASS\n");
1480
#endif
1481
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1482 1483
            for (k = 0; k<256; k++)
               if (filters_used[k])
1484
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1485
                     k, (unsigned long)filters_used[k]);
1486
#endif
1487
#ifdef PNG_TIME_RFC1123_SUPPORTED
1488 1489
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1490 1491 1492 1493 1494
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
         else
         {
1495 1496
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1497
         }
1498
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1499 1500
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1501
               current_allocation - allocation_now);
1502 1503
         if (current_allocation != 0)
         {
1504 1505 1506 1507
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
1508 1509
            while (pinfo != NULL)
            {
1510
               fprintf(STDERR, " %lu bytes at %x\n",
1511
                 (unsigned long)pinfo->size,
1512
                 (unsigned int) pinfo->pointer);
1513
               pinfo = pinfo->next;
1514
            }
1515
         }
1516 1517
#endif
      }
1518
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1519
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1520
            current_allocation);
1521
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1522
            maximum_allocation);
1523 1524 1525 1526
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1527
#endif
1528 1529 1530
   }
   else
   {
1531
      int i;
1532
      for (i = 0; i<3; ++i)
1533
      {
1534
         int kerror;
1535
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1536 1537
         int allocation_now = current_allocation;
#endif
1538
         if (i == 1) status_dots_requested = 1;
1539
         else if (verbose == 0)status_dots_requested = 0;
1540
         if (i == 0 || verbose == 1 || ierror != 0)
1541
            fprintf(STDERR, "\n Testing %s:", inname);
1542
         kerror = test_one_file(inname, outname);
1543
         if (kerror == 0)
1544
         {
1545
            if (verbose == 1 || i == 2)
1546
            {
1547
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1548
                int k;
1549
#endif
1550
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1551
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1552
                   (unsigned long)zero_samples);
1553 1554 1555
#else
                fprintf(STDERR, " PASS\n");
#endif
1556
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1557 1558
                for (k = 0; k<256; k++)
                   if (filters_used[k])
1559
                      fprintf(STDERR, " Filter %d was used %lu times\n",
1560
                         k, (unsigned long)filters_used[k]);
1561
#endif
1562
#ifdef PNG_TIME_RFC1123_SUPPORTED
1563 1564
             if (tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n", tIME_string);
1565 1566
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1567 1568 1569
         }
         else
         {
1570
            if (verbose == 0 && i != 2)
1571
               fprintf(STDERR, "\n Testing %s:", inname);
1572 1573
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1574
         }
1575
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1576 1577
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1578
               current_allocation - allocation_now);
1579 1580
         if (current_allocation != 0)
         {
1581
             memory_infop pinfo = pinformation;
1582

1583 1584
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
1585 1586
             while (pinfo != NULL)
             {
1587 1588
                fprintf(STDERR, " %lu bytes at %x\n",
                   (unsigned long)pinfo->size, (unsigned int)pinfo->pointer);
1589 1590 1591 1592
                pinfo = pinfo->next;
             }
          }
#endif
1593
       }
1594
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1595
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1596
          current_allocation);
1597
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1598
          maximum_allocation);
1599 1600 1601 1602
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1603
#endif
1604 1605
   }

1606 1607 1608 1609
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1610
   fprintf(STDERR, " CPU time used = %.3f seconds",
1611
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1612
   fprintf(STDERR, " (decoding %.3f,\n",
1613
      t_decode/(float)CLOCKS_PER_SEC);
1614
   fprintf(STDERR, "        encoding %.3f ,",
1615
      t_encode/(float)CLOCKS_PER_SEC);
1616
   fprintf(STDERR, " other %.3f seconds)\n\n",
1617 1618 1619
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1620
   if (ierror == 0)
1621
      fprintf(STDERR, " libpng passes test\n");
1622
   else
1623
      fprintf(STDERR, " libpng FAILS test\n");
1624
   return (int)(ierror != 0);
1625
}
1626

1627
/* Generate a compiler error if there is an old png.h in the search path. */
1628
typedef version_1_5_0beta08 your_png_h_is_not_version_1_5_0beta08;