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.4.0 [November 22, 2009]
5
 * Copyright (c) 1998-2009 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 272 273 274
{
   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.
    */
275
   check = fread(data, 1, length, (png_FILE_p)png_ptr->io_ptr);
276

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

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

291
static void
292
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
293
{
294
   png_size_t check;
295
   png_byte *n_data;
296
   png_FILE_p io_ptr;
297 298 299

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

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

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

350
   check = fwrite(data, 1, length, (png_FILE_p)png_ptr->io_ptr);
351 352 353 354 355 356
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
#else
357
/* This is the model-independent version. Since the standard I/O library
358 359 360 361 362 363 364 365
   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
366
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
367
{
368
   png_size_t check;
369
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
370
   png_FILE_p io_ptr;
371 372 373

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

/* 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
412
pngtest_warning(png_structp png_ptr, png_const_charp message)
413 414 415 416 417 418 419 420 421 422 423 424 425
{
   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
426
pngtest_error(png_structp png_ptr, png_const_charp message)
427
{
428
   pngtest_warning(png_ptr, message);
429
   /* We can return because png_error calls the default handler, which is
430 431
    * actually OK in this case.
    */
432
}
433
#endif /* !PNG_STDIO_SUPPORTED */
434 435
/* END of code to validate stdio-free compilation */

436
/* START of code to validate memory allocation and deallocation */
437
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
438 439

/* Allocate memory.  For reasonable files, size should never exceed
440 441 442 443 444 445 446 447
 * 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.
 */
448 449
typedef struct memory_information
{
450
   png_alloc_size_t          size;
451
   png_voidp                 pointer;
452 453 454 455 456 457 458
   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;
459 460
static int total_allocation = 0;
static int num_allocations = 0;
461

462 463
png_voidp png_debug_malloc
   PNGARG((png_structp png_ptr, png_alloc_size_t size));
464
void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
465 466

png_voidp
467
png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
468
{
469

470
   /* png_malloc has already tested for NULL; png_create_struct calls
471 472
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
473

474
   if (size == 0)
475
      return (NULL);
476 477 478 479

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

/* Free a pointer.  It is removed from the list at the same time. */
void
515
png_debug_free(png_structp png_ptr, png_voidp ptr)
516 517
{
   if (png_ptr == NULL)
518
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
519 520
   if (ptr == 0)
   {
521 522 523 524 525 526 527 528 529
#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;
530 531
      for (;;)
      {
532
         memory_infop pinfo = *ppinfo;
533 534
         if (pinfo->pointer == ptr)
         {
535 536 537 538 539
            *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
540
               the memory that is to be freed. */
541
            png_memset(ptr, 0x55, pinfo->size);
542
            png_free_default(png_ptr, pinfo);
543
            pinfo = NULL;
544 545
            break;
         }
546 547
         if (pinfo->next == NULL)
         {
548
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
549 550 551 552 553 554 555
            break;
         }
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
556 557
   if (verbose)
      printf("Freeing %x\n", ptr);
558
   png_free_default(png_ptr, ptr);
559
   ptr = NULL;
560
}
561
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
562 563
/* END of code to test memory allocation/deallocation */

564 565

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

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

static png_uint_32 user_chunk_data[4];

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

static int read_user_chunk_callback(png_struct *png_ptr,
   png_unknown_chunkp chunk)
{
582 583 584 585 586 587 588 589 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
   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);
627 628 629 630 631

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

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

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

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

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

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

677
   png_debug(0, "Allocating read and write structures");
678
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
679 680 681 682
   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);
683
#else
684 685
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
686
#endif
687
#ifndef PNG_STDIO_SUPPORTED
688 689
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
690
#endif
691

692
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
693 694 695 696 697 698
   user_chunk_data[0] = 0;
   user_chunk_data[1] = 0;
   user_chunk_data[2] = 0;
   user_chunk_data[3] = 0;
   png_set_read_user_chunk_fn(read_ptr, user_chunk_data,
     read_user_chunk_callback);
699

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

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

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

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

803
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
804
   {
805 806 807 808
      int i;
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
      png_set_read_user_transform_fn(read_ptr, count_filters);
809 810
   }
#endif
811
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
812
   zero_samples = 0;
813 814
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
815

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

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

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

A
Andreas Dilger 已提交
838 839 840 841
      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
          &color_type, &interlace_type, &compression_type, &filter_type))
      {
         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
842
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
843
            color_type, interlace_type, compression_type, filter_type);
844 845 846
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
847 848
      }
   }
849 850
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
851
   {
852
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
853 854 855
         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 已提交
856
      {
857 858
         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
A
Andreas Dilger 已提交
859
      }
G
Guy Schalnat 已提交
860
   }
A
Andreas Dilger 已提交
861
#endif
862
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
863
   {
864
      png_fixed_point gamma;
G
Guy Schalnat 已提交
865

866 867
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
868 869
   }
#endif
870
#else /* Use floating point versions */
871 872
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
873 874 875 876 877 878 879 880 881 882 883
   {
      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
884
#ifdef PNG_gAMA_SUPPORTED
885 886 887 888 889 890 891
   {
      double gamma;

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

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

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

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

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

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

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

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

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

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

1089
#ifdef PNG_WRITE_SUPPORTED
1090
   png_debug(0, "Writing info struct");
1091 1092

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

1097
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1098 1099
   if (user_chunk_data[0] != 0)
   {
1100
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1101

1102 1103
      unsigned char
        ster_chunk_data[1];
1104

1105 1106 1107 1108 1109
      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);
1110 1111 1112
   }
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
      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);
1127 1128 1129
   }

#endif
1130
#endif
A
Andreas Dilger 已提交
1131

1132
#ifdef SINGLE_ROWBUF_ALLOC
1133
   png_debug(0, "Allocating row buffer...");
1134
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1135
      png_get_rowbytes(read_ptr, read_info_ptr));
1136
   png_debug1(0, "0x%08lx", (unsigned long)row_buf);
1137
#endif /* SINGLE_ROWBUF_ALLOC */
1138
   png_debug(0, "Writing row data");
A
Andreas Dilger 已提交
1139

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

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

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

#ifndef SINGLE_ROWBUF_ALLOC
1184
         png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y);
1185
         png_free(read_ptr, row_buf);
1186
         row_buf = NULL;
1187
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1188 1189 1190
      }
   }

1191
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1192
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1193
#endif
1194
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1195
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1196 1197
#endif

1198
   png_debug(0, "Reading and writing end_info data");
1199

A
Andreas Dilger 已提交
1200
   png_read_end(read_ptr, end_info_ptr);
1201
#ifdef PNG_TEXT_SUPPORTED
1202 1203 1204 1205 1206 1207
   {
      png_textp text_ptr;
      int num_text;

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

1258
#ifdef PNG_EASY_ACCESS_SUPPORTED
1259
   if (verbose)
1260 1261 1262 1263
   {
      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);
1264
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1265
         (unsigned long)iwidth, (unsigned long)iheight);
1266 1267
   }
#endif
G
Guy Schalnat 已提交
1268

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

1285 1286
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1287

1288
   png_debug(0, "Opening files for comparison");
A
Andreas Dilger 已提交
1289
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1290
   {
G
Guy Schalnat 已提交
1291
      fprintf(STDERR, "Could not find file %s\n", inname);
1292
      return (1);
G
Guy Schalnat 已提交
1293 1294
   }

A
Andreas Dilger 已提交
1295
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1296
   {
G
Guy Schalnat 已提交
1297
      fprintf(STDERR, "Could not find file %s\n", outname);
1298
      FCLOSE(fpin);
1299
      return (1);
G
Guy Schalnat 已提交
1300
   }
A
Andreas Dilger 已提交
1301

1302
   for (;;)
G
Guy Schalnat 已提交
1303
   {
A
Andreas Dilger 已提交
1304
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1305

1306 1307
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1308 1309 1310

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

      if (!num_in)
         break;

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

1354 1355
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1356

1357
   return (0);
G
Guy Schalnat 已提交
1358
}
G
Guy Schalnat 已提交
1359

1360
/* Input and output filenames */
1361
#ifdef RISCOS
1362 1363
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1364
#else
1365 1366
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1367 1368 1369 1370 1371 1372 1373 1374
#endif

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

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

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

   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)
   {
1412
      if (strcmp(argv[1], "-m") == 0)
1413
      {
1414
         multiple = 1;
1415 1416
         status_dots_requested = 0;
      }
1417 1418 1419 1420 1421
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1422
         status_dots_requested = 1;
1423 1424 1425 1426
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1427
         status_dots_requested = 1;
1428 1429 1430
         inname = argv[2];
      }
      else
1431
      {
1432
         inname = argv[1];
1433 1434
         status_dots_requested = 0;
      }
1435 1436
   }

1437 1438
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1439

1440
   if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2))
1441
   {
1442 1443
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1444
        argv[0], argv[0]);
1445 1446 1447 1448
     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);
1449 1450 1451 1452 1453 1454
     exit(1);
   }

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

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

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

1600 1601 1602 1603
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
1604
   fprintf(STDERR, " CPU time used = %.3f seconds",
1605
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1606
   fprintf(STDERR, " (decoding %.3f,\n",
1607
      t_decode/(float)CLOCKS_PER_SEC);
1608
   fprintf(STDERR, "        encoding %.3f ,",
1609
      t_encode/(float)CLOCKS_PER_SEC);
1610
   fprintf(STDERR, " other %.3f seconds)\n\n",
1611 1612 1613
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1614
   if (ierror == 0)
1615
      fprintf(STDERR, " libpng passes test\n");
1616
   else
1617
      fprintf(STDERR, " libpng FAILS test\n");
1618
   return (int)(ierror != 0);
1619
}
1620

1621
/* Generate a compiler error if there is an old png.h in the search path. */
1622
typedef version_1_4_0beta105 your_png_h_is_not_version_1_4_0beta105;