pngtest.c 47.7 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.4.0 [July 22, 2008]
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2008 Glenn Randers-Pehrson
7 8
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9 10 11 12 13 14 15
 *
 * 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.
 *
16
 * The program will report "FAIL" in certain legitimate cases:
17
 * 1) when the compression level or filter selection method is changed.
18
 * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
19 20
 * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
 *    exist in the input file.
21 22
 * 4) others not listed here...
 * In these cases, it is best to check with another tool such as "pngcheck"
23
 * to see what the differences between the two files are.
24 25 26
 *
 * 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
27 28
 * 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 ..."
29
 */
G
Guy Schalnat 已提交
30

31
#include "png.h"
32
#include "pngpriv.h"
33

34 35 36
#  include <stdio.h>
#  include <stdlib.h>
#  define FCLOSE(file) fclose(file)
37

38 39
#if defined(PNG_NO_STDIO)
     typedef FILE                * png_FILE_p;
40 41
#endif

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

#if !PNG_DEBUG
48
#  define SINGLE_ROWBUF_ALLOC  /* makes buffer overruns easier to nail */
49
#endif
A
Andreas Dilger 已提交
50

51 52 53 54
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

55 56 57 58
#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
#undef PNGTEST_TIMING
#endif

59 60 61 62 63
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

64 65 66 67 68 69
#if defined(PNG_TIME_RFC1123_SUPPORTED)
#define PNG_tIME_STRING_LENGTH 30
static int tIME_chunk_present = 0;
static char tIME_string[PNG_tIME_STRING_LENGTH] = "no tIME chunk present in file";
#endif

70 71
static int verbose = 0;

72
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
73

G
Guy Schalnat 已提交
74 75 76 77 78
#ifdef __TURBOC__
#include <mem.h>
#endif

/* defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
79
/*  #define STDERR stderr  */
G
Guy Schalnat 已提交
80
#define STDERR stdout   /* for DOS */
G
Guy Schalnat 已提交
81

82 83 84 85 86 87 88 89 90 91
/* 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

92
/* example of using row callbacks to make a simple progress meter */
93 94 95
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
96

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

118
void
119
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
120
void
121
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
122
{
123
    if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) return;
124 125 126 127
    fprintf(stdout, "w");
}


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

143
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
144
/* example of using user transform callback (we don't transform anything,
145
   but merely count the zero samples) */
146

147
static png_uint_32 zero_samples;
148

149 150
void
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
151
void
152
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
153 154
{
   png_bytep dp = data;
155
   if (png_ptr == NULL)return;
156 157 158 159 160 161 162 163 164 165

   /* contents of row_info:
    *  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)
    */

166

167
    /* counts the number of zero samples (or zero pixels if color_type is 3 */
168

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

218
       for (n = 0, nstop=row_info->width; n<nstop; n++)
219 220 221
       {
          for (channel = 0; channel < color_channels; channel++)
          {
222 223 224
             if (row_info->bit_depth == 8)
                if (*dp++ == 0) zero_samples++;
             if (row_info->bit_depth == 16)
225
             {
226
                if ((*dp | *(dp+1)) == 0) zero_samples++;
227 228 229
                dp+=2;
             }
          }
230
          if (row_info->color_type > 3)
231 232
          {
             dp++;
233
             if (row_info->bit_depth == 16)dp++;
234 235 236 237
          }
       }
    }
}
238
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
239

240
static int wrote_question = 0;
241

242
#if defined(PNG_NO_STDIO)
243 244 245
/* START of code to validate stdio-free compilation */
/* 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. */
246
/* This is the function that does the actual reading of data.  If you are
247 248 249
   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. */
250

251 252
#ifndef USE_FAR_KEYWORD
static void
253
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
254 255 256 257 258 259
{
   png_size_t check;

   /* 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.
    */
260
   check = fread(data, 1, length, (png_FILE_p)png_ptr->io_ptr);
261

262 263
   if (check != length)
   {
264
      png_error(png_ptr, "Read Error!");
265 266
   }
}
G
Guy Schalnat 已提交
267
#else
268 269 270 271
/* this is the model-independent version. Since the standard I/O library
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
272

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

276
static void
277
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
278
{
279
   png_size_t check;
280
   png_byte *n_data;
281
   png_FILE_p io_ptr;
282 283 284

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
285
   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
286 287
   if ((png_bytep)n_data == data)
   {
288
      check = fread(n_data, 1, length, io_ptr);
289 290 291 292 293 294 295 296 297 298
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
299
         err = fread(buf, 1, 1, io_ptr);
300
         png_memcpy(data, buf, read); /* copy far buffer to near buffer */
301
         if (err != read)
302 303 304 305 306 307 308 309 310 311 312 313 314
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
   if (check != length)
   {
      png_error(png_ptr, "read Error");
   }
}
315
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
316

317
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
318
static void
319
pngtest_flush(png_structp png_ptr)
320
{
321 322
   png_FILE_p io_ptr;
   io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
323 324 325 326
   if (io_ptr != NULL)
      fflush(io_ptr);
}
#endif
G
Guy Schalnat 已提交
327

328
/* This is the function that does the actual writing of data.  If you are
329 330 331 332 333
   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. */
#ifndef USE_FAR_KEYWORD
static void
334
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
335
{
336
   png_size_t check;
337

338
   check = fwrite(data, 1, length, (png_FILE_p)png_ptr->io_ptr);
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
#else
/* this is the model-independent version. Since the standard I/O library
   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
354
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
355
{
356
   png_size_t check;
357
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
358
   png_FILE_p io_ptr;
359 360 361

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
362
   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
363 364
   if ((png_bytep)near_data == data)
   {
365
      check = fwrite(near_data, 1, length, io_ptr);
366 367 368 369 370 371 372 373 374 375 376
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
         png_memcpy(buf, data, written); /* copy far buffer to near buffer */
377
         err = fwrite(buf, 1, written, io_ptr);
378 379 380 381 382 383 384 385 386 387 388 389 390 391
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
392
#endif /* USE_FAR_KEYWORD */
393 394 395 396 397 398 399

/* 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
400
pngtest_warning(png_structp png_ptr, png_const_charp message)
401 402 403 404 405 406 407 408 409 410 411 412 413
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
   if (png_ptr != NULL && png_ptr->error_ptr != NULL)
      name = png_ptr->error_ptr;
   fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
}

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

423
/* START of code to validate memory allocation and deallocation */
424
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
425 426 427 428 429 430 431 432 433

/* Allocate memory.  For reasonable files, size should never exceed
   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. */
434 435
typedef struct memory_information
{
436
   png_alloc_size_t          size;
437
   png_voidp                 pointer;
438 439 440 441 442 443 444
   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;
445 446
static int total_allocation = 0;
static int num_allocations = 0;
447

448 449
png_voidp png_debug_malloc
   PNGARG((png_structp png_ptr, png_alloc_size_t size));
450
void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
451 452

png_voidp
453
png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
454
{
455

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

459
   if (size == 0)
460
      return (NULL);
461 462 463 464

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
465
      /* Disable malloc_fn and free_fn */
466
      memory_infop pinfo;
467
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
468 469
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
470 471
      pinfo->size = size;
      current_allocation += size;
472 473
      total_allocation += size;
      num_allocations ++;
474 475
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
476
      pinfo->pointer = png_malloc(png_ptr, size);
477
      /* Restore malloc_fn and free_fn */
478 479
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
480 481 482 483
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
484
         png_error(png_ptr,
485
           "out of memory in pngtest->png_debug_malloc");
486
      }
487 488 489 490
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
491 492
      if (verbose)
         printf("png_malloc %lu bytes at %x\n", (unsigned long)size,
493
            pinfo->pointer);
494
      return (png_voidp)(pinfo->pointer);
495 496 497 498 499
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
void
500
png_debug_free(png_structp png_ptr, png_voidp ptr)
501 502
{
   if (png_ptr == NULL)
503
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
504 505
   if (ptr == 0)
   {
506 507 508 509 510 511 512 513 514
#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;
515 516
      for (;;)
      {
517
         memory_infop pinfo = *ppinfo;
518 519
         if (pinfo->pointer == ptr)
         {
520 521 522 523 524
            *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
525
               the memory that is to be freed. */
526
            png_memset(ptr, 0x55, pinfo->size);
527
            png_free_default(png_ptr, pinfo);
528
            pinfo=NULL;
529 530
            break;
         }
531 532
         if (pinfo->next == NULL)
         {
533
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
534 535 536 537 538 539 540
            break;
         }
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
541 542
   if (verbose)
      printf("Freeing %x\n", ptr);
543
   png_free_default(png_ptr, ptr);
544
   ptr=NULL;
545
}
546
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
547 548
/* END of code to test memory allocation/deallocation */

549 550 551 552 553 554 555 556 557

/* Demonstration of user chunk support of the sTER and vpAg chunks */
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)

/* (sTER is a public chunk not yet understood by libpng.  vpAg is a private
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

558 559 560 561
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
     */

static int read_user_chunk_callback(png_struct *png_ptr,
   png_unknown_chunkp chunk)
{
  png_uint_32
    *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 */
584
      chunk->name[2] ==  69 && chunk->name[3] ==  82)       /* E  R */
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
     {
       /* Found sTER chunk */
       if (chunk->size != 1)
         return (-1); /* Error return */
       if (chunk->data[0] != 0 && chunk->data[0] != 1)
          return (-1);  /* Invalid mode */
       user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);
       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 */

  user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr);

606 607
  user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data);
  user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4);
608
  user_chunk_data[3]=(png_uint_32)chunk->data[8];
609 610 611 612 613 614 615

  return (1);

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

616
/* Test one file */
617 618
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
619
{
620 621
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
622 623 624 625 626 627 628 629 630 631 632
   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 已提交
633
   png_bytep row_buf;
G
Guy Schalnat 已提交
634
   png_uint_32 y;
A
Andreas Dilger 已提交
635 636 637
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
638
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
639
#ifdef USE_FAR_KEYWORD
640
   jmp_buf jmpbuf;
641
#endif
642
#endif
643

644
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
645

646
   row_buf = NULL;
G
Guy Schalnat 已提交
647

A
Andreas Dilger 已提交
648
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
649 650
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
651
      return (1);
G
Guy Schalnat 已提交
652 653
   }

A
Andreas Dilger 已提交
654
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
655
   {
G
Guy Schalnat 已提交
656
      fprintf(STDERR, "Could not open output file %s\n", outname);
657
      FCLOSE(fpin);
658
      return (1);
G
Guy Schalnat 已提交
659 660
   }

A
Andreas Dilger 已提交
661
   png_debug(0, "Allocating read and write structures\n");
662
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
663 664 665 666
   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);
667
#else
668 669
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
670
#endif
671
#if defined(PNG_NO_STDIO)
672 673
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
674
#endif
675 676

#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
677 678 679 680
  user_chunk_data[0] = 0;
  user_chunk_data[1] = 0;
  user_chunk_data[2] = 0;
  user_chunk_data[3] = 0;
681 682 683
  png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
    read_user_chunk_callback);

684
#endif
685
#ifdef PNG_WRITE_SUPPORTED
686
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
687 688 689
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
690
#else
691 692
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
693
#endif
694
#if defined(PNG_NO_STDIO)
695 696
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
697
#endif
698
#endif
A
Andreas Dilger 已提交
699 700
   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
   read_info_ptr = png_create_info_struct(read_ptr);
701
   end_info_ptr = png_create_info_struct(read_ptr);
702 703
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
704
   write_end_info_ptr = png_create_info_struct(write_ptr);
705
#endif
G
Guy Schalnat 已提交
706

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

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

A
Andreas Dilger 已提交
755
   png_debug(0, "Initializing input and output streams\n");
756
#if !defined(PNG_NO_STDIO)
G
Guy Schalnat 已提交
757
   png_init_io(read_ptr, fpin);
758
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
759
   png_init_io(write_ptr, fpout);
760
#  endif
761
#else
762
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
763
#  ifdef PNG_WRITE_SUPPORTED
764
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
765
#    if defined(PNG_WRITE_FLUSH_SUPPORTED)
766
      pngtest_flush);
767
#    else
768
      NULL);
769 770
#    endif
#  endif
771
#endif
772
   if (status_dots_requested == 1)
773
   {
774
#ifdef PNG_WRITE_SUPPORTED
775
      png_set_write_status_fn(write_ptr, write_row_callback);
776
#endif
777 778 779 780
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
   else
   {
781
#ifdef PNG_WRITE_SUPPORTED
782
      png_set_write_status_fn(write_ptr, NULL);
783
#endif
784
      png_set_read_status_fn(read_ptr, NULL);
785 786
   }

787 788 789
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
   {
     int i;
790 791
     for (i = 0; i<256; i++)
        filters_used[i] = 0;
792 793 794 795
     png_set_read_user_transform_fn(read_ptr, count_filters);
   }
#endif
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
796
   zero_samples = 0;
797 798
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
799

800
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
801 802 803
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
804 805
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
806 807
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
808 809 810
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
811 812
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
813 814
#endif

A
Andreas Dilger 已提交
815 816
   png_debug(0, "Reading info struct\n");
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
817

A
Andreas Dilger 已提交
818 819 820
   png_debug(0, "Transferring info struct\n");
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
821

A
Andreas Dilger 已提交
822 823 824 825
      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,
826
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
827
            color_type, interlace_type, compression_type, filter_type);
828 829 830
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
831 832
      }
   }
833
#if defined(PNG_FIXED_POINT_SUPPORTED)
834
#if defined(PNG_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
835
   {
836
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
837 838 839
         blue_y;
      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 已提交
840
      {
841 842
         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 已提交
843
      }
G
Guy Schalnat 已提交
844
   }
A
Andreas Dilger 已提交
845
#endif
846
#if defined(PNG_gAMA_SUPPORTED)
A
Andreas Dilger 已提交
847
   {
848
      png_fixed_point gamma;
G
Guy Schalnat 已提交
849

850
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
A
Andreas Dilger 已提交
851
      {
852
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
853 854 855
      }
   }
#endif
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
#else /* Use floating point versions */
#if defined(PNG_FLOATING_POINT_SUPPORTED)
#if defined(PNG_cHRM_SUPPORTED)
   {
      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
#if defined(PNG_gAMA_SUPPORTED)
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
      {
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
      }
   }
#endif
#endif /* floating point */
#endif /* fixed point */
882
#if defined(PNG_iCCP_SUPPORTED)
G
Guy Schalnat 已提交
883
   {
884 885
      png_charp name;
      png_charp profile;
886
      png_uint_32 proflen;
887
      int compression_type;
A
Andreas Dilger 已提交
888

889 890
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
891
      {
892 893
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
894
      }
G
Guy Schalnat 已提交
895
   }
896
#endif
897
#if defined(PNG_sRGB_SUPPORTED)
898
   {
899
      int intent;
900 901 902 903 904 905

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
      {
         png_set_sRGB(write_ptr, write_info_ptr, intent);
      }
   }
A
Andreas Dilger 已提交
906
#endif
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
   {
      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);
      }
   }
#if defined(PNG_bKGD_SUPPORTED)
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
#if defined(PNG_hIST_SUPPORTED)
G
Guy Schalnat 已提交
927
   {
A
Andreas Dilger 已提交
928 929 930 931 932 933
      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 已提交
934
   }
A
Andreas Dilger 已提交
935
#endif
936
#if defined(PNG_oFFs_SUPPORTED)
A
Andreas Dilger 已提交
937
   {
938
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
939
      int unit_type;
G
Guy Schalnat 已提交
940

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

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

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

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

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1018
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
A
Andreas Dilger 已提交
1019 1020 1021 1022
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1023
#if defined(PNG_tIME_SUPPORTED)
A
Andreas Dilger 已提交
1024 1025 1026 1027 1028 1029
   {
      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);
1030
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1031
         /* we have to use png_memcpy instead of "=" because the string
1032 1033
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1034 1035 1036 1037
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1038 1039
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1040
      }
A
Andreas Dilger 已提交
1041 1042
   }
#endif
1043
#if defined(PNG_tRNS_SUPPORTED)
A
Andreas Dilger 已提交
1044 1045 1046 1047 1048 1049 1050 1051
   {
      png_bytep trans;
      int num_trans;
      png_color_16p trans_values;

      if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
         &trans_values))
      {
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
         int sample_max = (1 << read_info_ptr->bit_depth);
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
         if (!((read_info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
            (int)trans_values->gray > sample_max) ||
            (read_info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
            ((int)trans_values->red > sample_max ||
            (int)trans_values->green > sample_max ||
            (int)trans_values->blue > sample_max))))
           png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
              trans_values);
A
Andreas Dilger 已提交
1062 1063 1064
      }
   }
#endif
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   {
      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);
         /* copy the locations from the read_info_ptr.  The automatically
            generated locations in write_info_ptr are wrong because we
            haven't written anything yet */
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1079 1080
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1081 1082 1083
      }
   }
#endif
A
Andreas Dilger 已提交
1084

1085
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1086
   png_debug(0, "\nWriting info struct\n");
1087 1088 1089 1090

/* If we wanted, we could write info in two steps:
   png_write_info_before_PLTE(write_ptr, write_info_ptr);
 */
A
Andreas Dilger 已提交
1091
   png_write_info(write_ptr, write_info_ptr);
1092 1093 1094 1095 1096 1097 1098 1099 1100

#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
   if (user_chunk_data[0] != 0)
   {
     png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};

     unsigned char
       ster_chunk_data[1];

1101
     if (verbose)
1102
        fprintf(STDERR, "stereo mode = %lu\n",
1103 1104 1105
          (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);
1106 1107 1108 1109 1110 1111 1112 1113
   }
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
     png_byte png_vpAg[5] = {118, 112,  65, 103, '\0'};

     unsigned char
       vpag_chunk_data[9];

1114
     if (verbose)
1115 1116 1117 1118
        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]);
1119 1120 1121 1122
     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);
1123 1124 1125
   }

#endif
1126
#endif
A
Andreas Dilger 已提交
1127

1128 1129
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(0, "\nAllocating row buffer...");
1130
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1131
      png_get_rowbytes(read_ptr, read_info_ptr));
1132 1133
   png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
#endif /* SINGLE_ROWBUF_ALLOC */
1134
   png_debug(0, "Writing row data\n");
A
Andreas Dilger 已提交
1135

1136 1137
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1138
   num_pass = png_set_interlace_handling(read_ptr);
1139
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1140
   png_set_interlace_handling(write_ptr);
1141
#  endif
1142
#else
1143
   num_pass = 1;
1144
#endif
A
Andreas Dilger 已提交
1145

1146 1147 1148 1149 1150
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1151 1152
   for (pass = 0; pass < num_pass; pass++)
   {
1153
      png_debug1(0, "Writing row data for pass %d\n", pass);
A
Andreas Dilger 已提交
1154 1155
      for (y = 0; y < height; y++)
      {
1156
#ifndef SINGLE_ROWBUF_ALLOC
1157
         png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass, y);
1158 1159 1160 1161 1162
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
         png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
            png_get_rowbytes(read_ptr, read_info_ptr));
#endif /* !SINGLE_ROWBUF_ALLOC */
1163
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1164 1165

#ifdef PNG_WRITE_SUPPORTED
1166 1167 1168 1169 1170
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1171
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1172 1173 1174 1175 1176
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1177 1178 1179 1180 1181 1182
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
         png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y);
         png_free(read_ptr, row_buf);
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1183 1184 1185
      }
   }

1186
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1187
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1188 1189
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1190
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1191 1192
#endif

A
Andreas Dilger 已提交
1193
   png_debug(0, "Reading and writing end_info data\n");
1194

A
Andreas Dilger 已提交
1195
   png_read_end(read_ptr, end_info_ptr);
1196
#if defined(PNG_TEXT_SUPPORTED)
1197 1198 1199 1200 1201 1202
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1203
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1204 1205 1206 1207
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1208
#if defined(PNG_tIME_SUPPORTED)
1209 1210 1211 1212 1213 1214 1215
   {
      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);
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1216
         /* we have to use png_memcpy instead of "=" because the string
1217 1218
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1219 1220 1221 1222
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1223 1224 1225 1226
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   {
      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);
         /* copy the locations from the read_info_ptr.  The automatically
            generated locations in write_end_info_ptr are wrong because we
            haven't written the end_info yet */
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1243 1244
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1245 1246
      }
   }
1247
#endif
1248
#ifdef PNG_WRITE_SUPPORTED
1249
   png_write_end(write_ptr, write_end_info_ptr);
1250
#endif
1251

1252
#ifdef PNG_EASY_ACCESS_SUPPORTED
1253
   if (verbose)
1254 1255 1256 1257 1258
   {
      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);
      fprintf(STDERR, "Image width = %lu, height = %lu\n",
1259
         (unsigned long)iwidth, (unsigned long)iheight);
1260 1261
   }
#endif
G
Guy Schalnat 已提交
1262

A
Andreas Dilger 已提交
1263
   png_debug(0, "Destroying data structs\n");
1264 1265
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(1, "destroying row_buf for read_ptr\n");
1266
   png_free(read_ptr, row_buf);
1267
   row_buf=NULL;
1268 1269
#endif /* SINGLE_ROWBUF_ALLOC */
   png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
A
Andreas Dilger 已提交
1270
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1271 1272
#ifdef PNG_WRITE_SUPPORTED
   png_debug(1, "destroying write_end_info_ptr\n");
1273
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1274
   png_debug(1, "destroying write_ptr, write_info_ptr\n");
A
Andreas Dilger 已提交
1275
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1276 1277
#endif
   png_debug(0, "Destruction complete.\n");
G
Guy Schalnat 已提交
1278

1279 1280
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1281

A
Andreas Dilger 已提交
1282 1283
   png_debug(0, "Opening files for comparison\n");
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1284
   {
G
Guy Schalnat 已提交
1285
      fprintf(STDERR, "Could not find file %s\n", inname);
1286
      return (1);
G
Guy Schalnat 已提交
1287 1288
   }

A
Andreas Dilger 已提交
1289
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1290
   {
G
Guy Schalnat 已提交
1291
      fprintf(STDERR, "Could not find file %s\n", outname);
1292
      FCLOSE(fpin);
1293
      return (1);
G
Guy Schalnat 已提交
1294
   }
A
Andreas Dilger 已提交
1295

1296
   for (;;)
G
Guy Schalnat 已提交
1297
   {
A
Andreas Dilger 已提交
1298
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1299

1300 1301
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1302 1303 1304

      if (num_in != num_out)
      {
1305
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1306
                 inname, outname);
1307
         if (wrote_question == 0)
1308 1309
         {
            fprintf(STDERR,
1310
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1311
              inname, PNG_ZBUF_SIZE);
1312
            fprintf(STDERR,
1313
              "\n   filtering heuristic (libpng default), compression");
1314
            fprintf(STDERR,
1315
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1316
              ZLIB_VERSION);
1317
            wrote_question = 1;
1318
         }
1319 1320
         FCLOSE(fpin);
         FCLOSE(fpout);
1321
         return (0);
G
Guy Schalnat 已提交
1322 1323 1324 1325 1326
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1327
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1328
      {
1329
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1330
         if (wrote_question == 0)
1331 1332
         {
            fprintf(STDERR,
1333
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1334
                 inname, PNG_ZBUF_SIZE);
1335
            fprintf(STDERR,
1336
              "\n   filtering heuristic (libpng default), compression");
1337
            fprintf(STDERR,
1338
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1339
              ZLIB_VERSION);
1340
            wrote_question = 1;
1341
         }
1342 1343
         FCLOSE(fpin);
         FCLOSE(fpout);
1344
         return (0);
G
Guy Schalnat 已提交
1345 1346 1347
      }
   }

1348 1349
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1350

1351
   return (0);
G
Guy Schalnat 已提交
1352
}
G
Guy Schalnat 已提交
1353

1354 1355
/* input and output filenames */
#ifdef RISCOS
1356 1357
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1358
#else
1359 1360
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1361 1362 1363 1364 1365 1366 1367 1368 1369
#endif

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

   fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1370
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1371
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1372
   /* Show the version of libpng used in building the library */
1373 1374
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1375
      png_get_header_version(NULL));
1376
   /* Show the version of libpng used in building the application */
1377
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1378
      PNG_HEADER_VERSION_STRING);
1379 1380
   fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
                    (long)png_sizeof(png_struct), (long)png_sizeof(png_info));
1381 1382 1383 1384 1385

   /* Do some consistency checking on the memory allocation settings, I'm
      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 */
1386
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1387
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1388
#endif
1389
   /* I think the following can happen. */
1390
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1391
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1392
#endif
1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

   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)
   {
1405
      if (strcmp(argv[1], "-m") == 0)
1406
      {
1407
         multiple = 1;
1408 1409
         status_dots_requested = 0;
      }
1410 1411 1412 1413 1414
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1415
         status_dots_requested = 1;
1416 1417 1418 1419
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1420
         status_dots_requested = 1;
1421 1422 1423
         inname = argv[2];
      }
      else
1424
      {
1425
         inname = argv[1];
1426 1427
         status_dots_requested = 0;
      }
1428 1429
   }

1430 1431
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1432

1433
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1434
   {
1435 1436
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1437
        argv[0], argv[0]);
1438 1439 1440 1441
     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);
1442 1443 1444 1445 1446 1447
     exit(1);
   }

   if (multiple)
   {
      int i;
1448
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1449 1450
      int allocation_now = current_allocation;
#endif
1451
      for (i=2; i<argc; ++i)
1452
      {
1453 1454 1455 1456
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
         int k;
#endif
         int kerror;
1457
         fprintf(STDERR, "Testing %s:", argv[i]);
1458
         kerror = test_one_file(argv[i], outname);
1459
         if (kerror == 0)
1460
         {
1461
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1462
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1463
               (unsigned long)zero_samples);
1464
#else
1465
            fprintf(STDERR, " PASS\n");
1466
#endif
1467
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1468 1469
            for (k = 0; k<256; k++)
               if (filters_used[k])
1470
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1471
                     k, (unsigned long)filters_used[k]);
1472
#endif
1473
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1474 1475
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1476 1477 1478 1479 1480
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
         else
         {
1481 1482
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1483
         }
1484
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1485 1486
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1487
               current_allocation - allocation_now);
1488 1489
         if (current_allocation != 0)
         {
1490 1491 1492 1493
            memory_infop pinfo = pinformation;

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

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

1593 1594 1595 1596
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1597
   fprintf(STDERR, " CPU time used = %.3f seconds",
1598
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1599
   fprintf(STDERR, " (decoding %.3f,\n",
1600
      t_decode/(float)CLOCKS_PER_SEC);
1601
   fprintf(STDERR, "        encoding %.3f ,",
1602
      t_encode/(float)CLOCKS_PER_SEC);
1603
   fprintf(STDERR, " other %.3f seconds)\n\n",
1604 1605 1606
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1607 1608 1609 1610
   if (ierror == 0)
      fprintf(STDERR, "libpng passes test\n");
   else
      fprintf(STDERR, "libpng FAILS test\n");
1611
   return (int)(ierror != 0);
1612
}
1613

1614
/* Generate a compiler error if there is an old png.h in the search path. */
1615
typedef version_1_4_0beta23 your_png_h_is_not_version_1_4_0beta23;