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

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

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

45
#ifndef PNG_STDIO_SUPPORTED
46
typedef FILE                * png_FILE_p;
47 48
#endif

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

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

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

G
[devel]  
Glenn Randers-Pehrson 已提交
68 69 70 71 72 73 74 75 76 77 78
/* The code uses memcmp and memcpy on large objects (typically row pointers) so
 * it is necessary to do soemthing special on certain architectures, note that
 * the actual support for this was effectively removed in 1.4, so only the
 * memory remains in this program:
 */
#define CVT_PTR(ptr)         (ptr)
#define CVT_PTR_NOCHECK(ptr) (ptr)
#define png_memcmp  memcmp
#define png_memcpy  memcpy
#define png_memset  memset

79 80 81 82
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

83
#ifndef PNG_FLOATING_POINT_SUPPORTED
84 85 86
#undef PNGTEST_TIMING
#endif

87 88 89 90 91
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

92
#ifdef PNG_TIME_RFC1123_SUPPORTED
93
#define PNG_tIME_STRING_LENGTH 29
94
static int tIME_chunk_present = 0;
95
static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
96 97
#endif

98 99
static int verbose = 0;

100
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
101

G
Guy Schalnat 已提交
102 103 104 105
#ifdef __TURBOC__
#include <mem.h>
#endif

106
/* Defined so I can write to a file on gui/windowing platforms */
G
Guy Schalnat 已提交
107
/*  #define STDERR stderr  */
108
#define STDERR stdout   /* For DOS */
G
Guy Schalnat 已提交
109

110 111 112 113 114
/* 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

115
/* Example of using row callbacks to make a simple progress meter */
116 117 118
static int status_pass = 1;
static int status_dots_requested = 0;
static int status_dots = 1;
119

120
void PNGCBAPI
121
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
122
void PNGCBAPI
123
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
124
{
125 126
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
      return;
127

128 129 130 131 132 133
   if (status_pass != pass)
   {
      fprintf(stdout, "\n Pass %d: ", pass);
      status_pass = pass;
      status_dots = 31;
   }
134

135
   status_dots--;
136

137 138 139 140 141
   if (status_dots == 0)
   {
      fprintf(stdout, "\n         ");
      status_dots=30;
   }
142

143
   fprintf(stdout, "r");
144
}
145

146
void PNGCBAPI
147
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
148
void PNGCBAPI
149
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
150
{
151 152
   if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
      return;
153

154
   fprintf(stdout, "w");
155 156 157
}


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

174
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
175
/* Example of using user transform callback (we don't transform anything,
176 177
 * but merely count the zero samples)
 */
178

179
static png_uint_32 zero_samples;
180

181
void PNGCBAPI
182
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
183
void PNGCBAPI
184
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
185 186
{
   png_bytep dp = data;
187 188
   if (png_ptr == NULL)
      return;
189

190
   /* Contents of row_info:
191 192 193 194 195 196 197 198
    *  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)
    */

199
    /* Counts the number of zero samples (or zero pixels if color_type is 3 */
200

201
    if (row_info->color_type == 0 || row_info->color_type == 3)
202
    {
203
       int pos = 0;
204
       png_uint_32 n, nstop;
205

206
       for (n = 0, nstop=row_info->width; n<nstop; n++)
207
       {
208
          if (row_info->bit_depth == 1)
209
          {
210 211
             if (((*dp << pos++ ) & 0x80) == 0)
                zero_samples++;
212

213
             if (pos == 8)
214
             {
215
                pos = 0;
216 217
                dp++;
             }
218
          }
219

220
          if (row_info->bit_depth == 2)
221
          {
222 223
             if (((*dp << (pos+=2)) & 0xc0) == 0)
                zero_samples++;
224

225
             if (pos == 8)
226
             {
227
                pos = 0;
228 229
                dp++;
             }
230
          }
231

232
          if (row_info->bit_depth == 4)
233
          {
234 235
             if (((*dp << (pos+=4)) & 0xf0) == 0)
                zero_samples++;
236

237
             if (pos == 8)
238
             {
239
                pos = 0;
240 241
                dp++;
             }
242
          }
243

244
          if (row_info->bit_depth == 8)
245 246
             if (*dp++ == 0)
                zero_samples++;
247

248
          if (row_info->bit_depth == 16)
249
          {
250 251
             if ((*dp | *(dp+1)) == 0)
                zero_samples++;
252 253 254 255
             dp+=2;
          }
       }
    }
256
    else /* Other color types */
257
    {
258
       png_uint_32 n, nstop;
259 260
       int channel;
       int color_channels = row_info->channels;
261
       if (row_info->color_type > 3)color_channels--;
262

263
       for (n = 0, nstop=row_info->width; n<nstop; n++)
264 265 266
       {
          for (channel = 0; channel < color_channels; channel++)
          {
267
             if (row_info->bit_depth == 8)
268 269
                if (*dp++ == 0)
                   zero_samples++;
270

271
             if (row_info->bit_depth == 16)
272
             {
273 274
                if ((*dp | *(dp+1)) == 0)
                   zero_samples++;
275

276 277 278
                dp+=2;
             }
          }
279
          if (row_info->color_type > 3)
280 281
          {
             dp++;
282 283
             if (row_info->bit_depth == 16)
                dp++;
284 285 286 287
          }
       }
    }
}
288
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
289

290
static int wrote_question = 0;
291

292
#ifndef PNG_STDIO_SUPPORTED
293
/* START of code to validate stdio-free compilation */
294 295 296 297 298 299 300
/* 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.
 */
301

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
#ifdef PNG_IO_STATE_SUPPORTED
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op);
void
pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
   png_uint_32 io_op)
{
   png_uint_32 io_state = png_get_io_state(png_ptr);
   int err = 0;

   /* Check if the current operation (reading / writing) is as expected. */
   if ((io_state & PNG_IO_MASK_OP) != io_op)
      png_error(png_ptr, "Incorrect operation in I/O state");

   /* Check if the buffer size specific to the current location
    * (file signature / header / data / crc) is as expected.
    */
   switch (io_state & PNG_IO_MASK_LOC)
   {
   case PNG_IO_SIGNATURE:
      if (data_length > 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_HDR:
      if (data_length != 8)
         err = 1;
      break;
   case PNG_IO_CHUNK_DATA:
      break;  /* no restrictions here */
   case PNG_IO_CHUNK_CRC:
      if (data_length != 4)
         err = 1;
      break;
   default:
      err = 1;  /* uninitialized */
   }
   if (err)
      png_error(png_ptr, "Bad I/O state or buffer size");
}
#endif

344
#ifndef USE_FAR_KEYWORD
345
static void PNGCBAPI
346
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
347
{
348 349
   png_size_t check = 0;
   png_voidp io_ptr;
350 351 352 353

   /* 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.
    */
354 355 356 357 358
   io_ptr = png_get_io_ptr(png_ptr);
   if (io_ptr != NULL)
   {
      check = fread(data, 1, length, (png_FILE_p)io_ptr);
   }
359

360 361
   if (check != length)
   {
362
      png_error(png_ptr, "Read Error");
363
   }
364 365 366 367

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
368
}
G
Guy Schalnat 已提交
369
#else
370
/* This is the model-independent version. Since the standard I/O library
371 372 373
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/
374

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

378
static void PNGCBAPI
379
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
380
{
381
   png_size_t check;
382
   png_byte *n_data;
383
   png_FILE_p io_ptr;
384 385 386

   /* Check if data really is near. If so, use usual code. */
   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
387
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
388 389
   if ((png_bytep)n_data == data)
   {
390
      check = fread(n_data, 1, length, io_ptr);
391 392 393 394 395 396 397
   }
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t read, remaining, err;
      check = 0;
      remaining = length;
398

399 400 401
      do
      {
         read = MIN(NEAR_BUF_SIZE, remaining);
402
         err = fread(buf, 1, 1, io_ptr);
403
         png_memcpy(data, buf, read); /* Copy far buffer to near buffer */
404
         if (err != read)
405 406 407 408 409 410 411 412
            break;
         else
            check += err;
         data += read;
         remaining -= read;
      }
      while (remaining != 0);
   }
413

414
   if (check != length)
415 416 417 418 419
      png_error(png_ptr, "Read Error");

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
#endif
420
}
421
#endif /* USE_FAR_KEYWORD */
G
Guy Schalnat 已提交
422

423
#ifdef PNG_WRITE_FLUSH_SUPPORTED
424
static void PNGCBAPI
425
pngtest_flush(png_structp png_ptr)
426
{
427
   /* Do nothing; fflush() is said to be just a waste of energy. */
428
   PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
429 430
}
#endif
G
Guy Schalnat 已提交
431

432
/* This is the function that does the actual writing of data.  If you are
433 434 435 436
 * 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.
 */
437
#ifndef USE_FAR_KEYWORD
438
static void PNGCBAPI
439
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
440
{
441
   png_size_t check;
442

443
   check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
444

445 446 447 448
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
449 450 451 452

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
453 454
}
#else
455
/* This is the model-independent version. Since the standard I/O library
456 457 458 459 460 461 462
   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)

463
static void PNGCBAPI
464
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
465
{
466
   png_size_t check;
467
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
468
   png_FILE_p io_ptr;
469 470 471

   /* Check if data really is near. If so, use usual code. */
   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
472
   io_ptr = (png_FILE_p)CVT_PTR(png_get_io_ptr(png_ptr));
473

474 475
   if ((png_bytep)near_data == data)
   {
476
      check = fwrite(near_data, 1, length, io_ptr);
477
   }
478

479 480 481 482 483 484
   else
   {
      png_byte buf[NEAR_BUF_SIZE];
      png_size_t written, remaining, err;
      check = 0;
      remaining = length;
485

486 487 488
      do
      {
         written = MIN(NEAR_BUF_SIZE, remaining);
489
         png_memcpy(buf, data, written); /* Copy far buffer to near buffer */
490
         err = fwrite(buf, 1, written, io_ptr);
491 492 493 494 495 496 497 498 499
         if (err != written)
            break;
         else
            check += err;
         data += written;
         remaining -= written;
      }
      while (remaining != 0);
   }
500

501 502 503 504
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
505 506 507 508

#ifdef PNG_IO_STATE_SUPPORTED
   pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif
509
}
510
#endif /* USE_FAR_KEYWORD */
511 512 513 514 515 516

/* 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.
 */
517
static void PNGCBAPI
518
pngtest_warning(png_structp png_ptr, png_const_charp message)
519 520
{
   PNG_CONST char *name = "UNKNOWN (ERROR!)";
521 522
   char *test;
   test = png_get_error_ptr(png_ptr);
523

524 525
   if (test == NULL)
     fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
526

527 528
   else
     fprintf(STDERR, "%s: libpng warning: %s\n", test, message);
529 530 531 532 533 534 535
}

/* 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().
 */
536
static void PNGCBAPI
537
pngtest_error(png_structp png_ptr, png_const_charp message)
538
{
539
   pngtest_warning(png_ptr, message);
540
   /* We can return because png_error calls the default handler, which is
541 542
    * actually OK in this case.
    */
543
}
544
#endif /* !PNG_STDIO_SUPPORTED */
545 546
/* END of code to validate stdio-free compilation */

547
/* START of code to validate memory allocation and deallocation */
548
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
549 550

/* Allocate memory.  For reasonable files, size should never exceed
551 552 553 554 555 556 557 558
 * 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.
 */
559 560
typedef struct memory_information
{
561
   png_alloc_size_t          size;
562
   png_voidp                 pointer;
563 564 565 566 567 568 569
   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;
570 571
static int total_allocation = 0;
static int num_allocations = 0;
572

573 574 575
png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr,
    png_alloc_size_t size));
void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
576 577

png_voidp
578
PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
579
{
580

581
   /* png_malloc has already tested for NULL; png_create_struct calls
582 583
    * png_debug_malloc directly, with png_ptr == NULL which is OK
    */
584

585
   if (size == 0)
586
      return (NULL);
587 588 589 590

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
591
      /* Disable malloc_fn and free_fn */
592
      memory_infop pinfo;
593
      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
594 595
      pinfo = (memory_infop)png_malloc(png_ptr,
         png_sizeof(*pinfo));
596 597
      pinfo->size = size;
      current_allocation += size;
598 599
      total_allocation += size;
      num_allocations ++;
600

601 602
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
603

604
      pinfo->pointer = png_malloc(png_ptr, size);
605
      /* Restore malloc_fn and free_fn */
606

607 608
      png_set_mem_fn(png_ptr,
          NULL, png_debug_malloc, png_debug_free);
609

610 611 612 613
      if (size != 0 && pinfo->pointer == NULL)
      {
         current_allocation -= size;
         total_allocation -= size;
614
         png_error(png_ptr,
615
           "out of memory in pngtest->png_debug_malloc");
616
      }
617

618 619 620 621
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
622

623
      if (verbose)
624
         printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
625
            pinfo->pointer);
626

627
      return (png_voidp)(pinfo->pointer);
628 629 630 631
   }
}

/* Free a pointer.  It is removed from the list at the same time. */
632
void PNGCBAPI
633
png_debug_free(png_structp png_ptr, png_voidp ptr)
634 635
{
   if (png_ptr == NULL)
636
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
637

638 639
   if (ptr == 0)
   {
640 641 642 643 644 645 646 647 648
#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;
649

650 651
      for (;;)
      {
652
         memory_infop pinfo = *ppinfo;
653

654 655
         if (pinfo->pointer == ptr)
         {
656 657 658 659 660
            *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
661
               the memory that is to be freed. */
662
            png_memset(ptr, 0x55, pinfo->size);
663
            png_free_default(png_ptr, pinfo);
664
            pinfo = NULL;
665 666
            break;
         }
667

668 669
         if (pinfo->next == NULL)
         {
670
            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
671 672
            break;
         }
673

674 675 676 677 678
         ppinfo = &pinfo->next;
      }
   }

   /* Finally free the data. */
679
   if (verbose)
680
      printf("Freeing %p\n", ptr);
681

682
   png_free_default(png_ptr, ptr);
683
   ptr = NULL;
684
}
685
#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
686 687
/* END of code to test memory allocation/deallocation */

688 689

/* Demonstration of user chunk support of the sTER and vpAg chunks */
690
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
691

692
/* (sTER is a public chunk not yet known by libpng.  vpAg is a private
693 694 695 696
chunk used in ImageMagick to store "virtual page" size).  */

static png_uint_32 user_chunk_data[4];

697 698 699 700
    /* 0: sTER mode + 1
     * 1: vpAg width
     * 2: vpAg height
     * 3: vpAg units
701 702
     */

703
static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr,
704 705
   png_unknown_chunkp chunk)
{
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
   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 */
728

729 730
         if (chunk->data[0] != 0 && chunk->data[0] != 1)
            return (-1);  /* Invalid mode */
731

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
         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);
753 754 755 756 757

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

758
/* Test one file */
759 760
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
761
{
762 763
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
764 765 766 767 768 769 770 771 772 773 774
   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 已提交
775
   png_bytep row_buf;
G
Guy Schalnat 已提交
776
   png_uint_32 y;
A
Andreas Dilger 已提交
777 778 779
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
780
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
781
#ifdef USE_FAR_KEYWORD
782
   jmp_buf png_jmpbuf;
783
#endif
784
#endif
785

786
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
787

788
   row_buf = NULL;
G
Guy Schalnat 已提交
789

A
Andreas Dilger 已提交
790
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
791 792
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
793
      return (1);
G
Guy Schalnat 已提交
794 795
   }

A
Andreas Dilger 已提交
796
   if ((fpout = fopen(outname, "wb")) == NULL)
G
Guy Schalnat 已提交
797
   {
G
Guy Schalnat 已提交
798
      fprintf(STDERR, "Could not open output file %s\n", outname);
799
      FCLOSE(fpin);
800
      return (1);
G
Guy Schalnat 已提交
801 802
   }

803
   pngtest_debug("Allocating read and write structures");
804
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
805 806
   read_ptr =
      png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
807
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
808
#else
809 810
   read_ptr =
      png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
811
#endif
812
#ifndef PNG_STDIO_SUPPORTED
813 814
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
815
#endif
816

817
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
818 819 820 821 822 823
   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);
824

825
#endif
826
#ifdef PNG_WRITE_SUPPORTED
827
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
828 829 830
   write_ptr =
      png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
      NULL, NULL, NULL, png_debug_malloc, png_debug_free);
831
#else
832 833
   write_ptr =
      png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
834
#endif
835
#ifndef PNG_STDIO_SUPPORTED
836 837
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
838
#endif
839
#endif
840
   pngtest_debug("Allocating read_info, write_info and end_info structures");
A
Andreas Dilger 已提交
841
   read_info_ptr = png_create_info_struct(read_ptr);
842
   end_info_ptr = png_create_info_struct(read_ptr);
843 844
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
845
   write_end_info_ptr = png_create_info_struct(write_ptr);
846
#endif
G
Guy Schalnat 已提交
847

848
#ifdef PNG_SETJMP_SUPPORTED
849
   pngtest_debug("Setting jmpbuf for read struct");
A
Andreas Dilger 已提交
850
#ifdef USE_FAR_KEYWORD
851
   if (setjmp(png_jmpbuf))
A
Andreas Dilger 已提交
852
#else
853
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
854
#endif
G
Guy Schalnat 已提交
855
   {
856
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
857 858
      png_free(read_ptr, row_buf);
      row_buf = NULL;
A
Andreas Dilger 已提交
859
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
860
#ifdef PNG_WRITE_SUPPORTED
861
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
862
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
863
#endif
864 865
      FCLOSE(fpin);
      FCLOSE(fpout);
866
      return (1);
G
Guy Schalnat 已提交
867
   }
868
#ifdef USE_FAR_KEYWORD
869
   png_memcpy(png_jmpbuf(read_ptr), png_jmpbuf, png_sizeof(jmp_buf));
870
#endif
A
Andreas Dilger 已提交
871

872
#ifdef PNG_WRITE_SUPPORTED
873
   pngtest_debug("Setting jmpbuf for write struct");
A
Andreas Dilger 已提交
874
#ifdef USE_FAR_KEYWORD
875

876
   if (setjmp(png_jmpbuf))
A
Andreas Dilger 已提交
877
#else
878
   if (setjmp(png_jmpbuf(write_ptr)))
A
Andreas Dilger 已提交
879
#endif
G
Guy Schalnat 已提交
880
   {
881
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
882
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
883
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
884
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
885
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
886
#endif
887 888
      FCLOSE(fpin);
      FCLOSE(fpout);
889
      return (1);
G
Guy Schalnat 已提交
890
   }
891

A
Andreas Dilger 已提交
892
#ifdef USE_FAR_KEYWORD
893
   png_memcpy(png_jmpbuf(write_ptr), png_jmpbuf, png_sizeof(jmp_buf));
894
#endif
895
#endif
A
Andreas Dilger 已提交
896
#endif
897

898
   pngtest_debug("Initializing input and output streams");
899
#ifdef PNG_STDIO_SUPPORTED
G
Guy Schalnat 已提交
900
   png_init_io(read_ptr, fpin);
901
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
902
   png_init_io(write_ptr, fpout);
903
#  endif
904
#else
905
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
906
#  ifdef PNG_WRITE_SUPPORTED
907
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
908
#    ifdef PNG_WRITE_FLUSH_SUPPORTED
909
      pngtest_flush);
910
#    else
911
      NULL);
912 913
#    endif
#  endif
914
#endif
915

916 917 918 919
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION
   png_set_text_compression_strategy(write_ptr, Z_FILTERED);
#endif

920
   if (status_dots_requested == 1)
921
   {
922
#ifdef PNG_WRITE_SUPPORTED
923
      png_set_write_status_fn(write_ptr, write_row_callback);
924
#endif
925 926
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
927

928 929
   else
   {
930
#ifdef PNG_WRITE_SUPPORTED
931
      png_set_write_status_fn(write_ptr, NULL);
932
#endif
933
      png_set_read_status_fn(read_ptr, NULL);
934 935
   }

936
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
937
   {
938
      int i;
939

940 941
      for (i = 0; i<256; i++)
         filters_used[i] = 0;
942

943
      png_set_read_user_transform_fn(read_ptr, count_filters);
944 945
   }
#endif
946
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
947
   zero_samples = 0;
948 949
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
950

951
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
952 953 954
#  ifndef PNG_HANDLE_CHUNK_ALWAYS
#    define PNG_HANDLE_CHUNK_ALWAYS       3
#  endif
955 956
   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
      NULL, 0);
957
#endif
958
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
959 960 961
#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
#    define PNG_HANDLE_CHUNK_IF_SAFE      2
#  endif
962 963
   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
      NULL, 0);
964 965
#endif

966
   pngtest_debug("Reading info struct");
A
Andreas Dilger 已提交
967
   png_read_info(read_ptr, read_info_ptr);
G
Guy Schalnat 已提交
968

969
   pngtest_debug("Transferring info struct");
A
Andreas Dilger 已提交
970 971
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
972

A
Andreas Dilger 已提交
973 974 975 976
      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,
977
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
A
Andreas Dilger 已提交
978
            color_type, interlace_type, compression_type, filter_type);
979 980 981
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
982 983
      }
   }
984 985
#ifdef PNG_FIXED_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
G
Guy Schalnat 已提交
986
   {
987
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
988
         blue_y;
989

990 991
      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 已提交
992
      {
993 994
         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 已提交
995
      }
G
Guy Schalnat 已提交
996
   }
A
Andreas Dilger 已提交
997
#endif
998
#ifdef PNG_gAMA_SUPPORTED
A
Andreas Dilger 已提交
999
   {
1000
      png_fixed_point gamma;
G
Guy Schalnat 已提交
1001

1002 1003
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
1004 1005
   }
#endif
1006
#else /* Use floating point versions */
1007 1008
#ifdef PNG_FLOATING_POINT_SUPPORTED
#ifdef PNG_cHRM_SUPPORTED
1009 1010 1011
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
1012

1013 1014 1015 1016 1017 1018 1019 1020
      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
1021
#ifdef PNG_gAMA_SUPPORTED
1022 1023 1024 1025 1026 1027 1028
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
   }
#endif
1029 1030
#endif /* Floating point */
#endif /* Fixed point */
1031
#ifdef PNG_iCCP_SUPPORTED
G
Guy Schalnat 已提交
1032
   {
1033
      png_charp name;
G
[devel]  
Glenn Randers-Pehrson 已提交
1034
      png_bytep profile;
1035
      png_uint_32 proflen;
1036
      int compression_type;
A
Andreas Dilger 已提交
1037

1038 1039
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
1040
      {
1041 1042
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
1043
      }
G
Guy Schalnat 已提交
1044
   }
1045
#endif
1046
#ifdef PNG_sRGB_SUPPORTED
1047
   {
1048
      int intent;
1049 1050 1051 1052

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
         png_set_sRGB(write_ptr, write_info_ptr, intent);
   }
A
Andreas Dilger 已提交
1053
#endif
1054 1055 1056 1057 1058 1059 1060
   {
      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);
   }
1061
#ifdef PNG_bKGD_SUPPORTED
1062 1063 1064 1065 1066 1067 1068 1069 1070
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
1071
#ifdef PNG_hIST_SUPPORTED
G
Guy Schalnat 已提交
1072
   {
A
Andreas Dilger 已提交
1073 1074 1075 1076
      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 已提交
1077
   }
A
Andreas Dilger 已提交
1078
#endif
1079
#ifdef PNG_oFFs_SUPPORTED
A
Andreas Dilger 已提交
1080
   {
1081
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
1082
      int unit_type;
G
Guy Schalnat 已提交
1083

1084
      if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1085
          &unit_type))
A
Andreas Dilger 已提交
1086 1087 1088 1089 1090
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
1091
#ifdef PNG_pCAL_SUPPORTED
A
Andreas Dilger 已提交
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
   {
      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
1106
#ifdef PNG_pHYs_SUPPORTED
A
Andreas Dilger 已提交
1107 1108 1109 1110 1111 1112 1113 1114
   {
      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
1115
#ifdef PNG_sBIT_SUPPORTED
A
Andreas Dilger 已提交
1116
   {
1117
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
1118

1119 1120
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
1121
   }
1122
#endif
1123
#ifdef PNG_sCAL_SUPPORTED
1124
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
1125
   {
1126
      int unit;
1127
      double scal_width, scal_height;
A
Andreas Dilger 已提交
1128

1129 1130
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
1131
      {
1132
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1133 1134 1135
      }
   }
#else
1136
#ifdef PNG_FIXED_POINT_SUPPORTED
1137
   {
1138
      int unit;
1139
      png_charp scal_width, scal_height;
1140

1141 1142
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
1143
      {
1144 1145
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
             scal_height);
A
Andreas Dilger 已提交
1146 1147
      }
   }
G
Guy Schalnat 已提交
1148
#endif
1149 1150
#endif
#endif
1151
#ifdef PNG_TEXT_SUPPORTED
A
Andreas Dilger 已提交
1152 1153 1154 1155 1156 1157
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
1158
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
A
Andreas Dilger 已提交
1159 1160 1161 1162
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
1163
#ifdef PNG_tIME_SUPPORTED
A
Andreas Dilger 已提交
1164 1165 1166 1167 1168 1169
   {
      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);
1170
#ifdef PNG_TIME_RFC1123_SUPPORTED
1171
         /* We have to use png_memcpy instead of "=" because the string
1172 1173 1174
          * pointed to by png_convert_to_rfc1123() gets free'ed before
          * we use it.
          */
1175 1176 1177
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1178

1179
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1180 1181
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
1182
      }
A
Andreas Dilger 已提交
1183 1184
   }
#endif
1185
#ifdef PNG_tRNS_SUPPORTED
A
Andreas Dilger 已提交
1186
   {
1187
      png_bytep trans_alpha;
A
Andreas Dilger 已提交
1188
      int num_trans;
1189
      png_color_16p trans_color;
A
Andreas Dilger 已提交
1190

1191
      if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1192
         &trans_color))
A
Andreas Dilger 已提交
1193
      {
1194
         int sample_max = (1 << bit_depth);
1195
         /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1196
         if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1197
             (int)trans_color->gray > sample_max) ||
1198
             (color_type == PNG_COLOR_TYPE_RGB &&
1199 1200 1201
             ((int)trans_color->red > sample_max ||
             (int)trans_color->green > sample_max ||
             (int)trans_color->blue > sample_max))))
1202
            png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1203
               trans_color);
A
Andreas Dilger 已提交
1204 1205 1206
      }
   }
#endif
1207
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1208 1209
   {
      png_unknown_chunkp unknowns;
1210
      int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1211
         &unknowns);
1212

1213 1214
      if (num_unknowns)
      {
1215
         int i;
1216 1217
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
1218
         /* Copy the locations from the read_info_ptr.  The automatically
1219 1220 1221
          * generated locations in write_info_ptr are wrong because we
          * haven't written anything yet.
          */
1222
         for (i = 0; i < num_unknowns; i++)
1223 1224
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1225 1226 1227
      }
   }
#endif
A
Andreas Dilger 已提交
1228

1229
#ifdef PNG_WRITE_SUPPORTED
1230
   pngtest_debug("Writing info struct");
1231 1232

/* If we wanted, we could write info in two steps:
1233
 * png_write_info_before_PLTE(write_ptr, write_info_ptr);
1234
 */
A
Andreas Dilger 已提交
1235
   png_write_info(write_ptr, write_info_ptr);
1236

1237
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1238 1239
   if (user_chunk_data[0] != 0)
   {
1240
      png_byte png_sTER[5] = {115,  84,  69,  82, '\0'};
1241

1242 1243
      unsigned char
        ster_chunk_data[1];
1244

1245 1246 1247
      if (verbose)
         fprintf(STDERR, "\n stereo mode = %lu\n",
           (unsigned long)(user_chunk_data[0] - 1));
1248

1249 1250
      ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1);
      png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1);
1251
   }
1252

1253 1254
   if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0)
   {
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
      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]);
1265

1266 1267 1268 1269
      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);
1270 1271 1272
   }

#endif
1273
#endif
A
Andreas Dilger 已提交
1274

1275
#ifdef SINGLE_ROWBUF_ALLOC
1276
   pngtest_debug("Allocating row buffer...");
1277
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1278
      png_get_rowbytes(read_ptr, read_info_ptr));
1279

1280
   pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1281
#endif /* SINGLE_ROWBUF_ALLOC */
1282
   pngtest_debug("Writing row data");
A
Andreas Dilger 已提交
1283

1284 1285
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1286
   num_pass = png_set_interlace_handling(read_ptr);
1287
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1288
   png_set_interlace_handling(write_ptr);
1289
#  endif
1290
#else
1291
   num_pass = 1;
1292
#endif
A
Andreas Dilger 已提交
1293

1294 1295 1296 1297 1298
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1299 1300
   for (pass = 0; pass < num_pass; pass++)
   {
1301
      pngtest_debug1("Writing row data for pass %d", pass);
A
Andreas Dilger 已提交
1302 1303
      for (y = 0; y < height; y++)
      {
1304
#ifndef SINGLE_ROWBUF_ALLOC
1305
         pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1306 1307
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
1308

1309
         pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf,
1310
            png_get_rowbytes(read_ptr, read_info_ptr));
1311

1312
#endif /* !SINGLE_ROWBUF_ALLOC */
1313
         png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1314 1315

#ifdef PNG_WRITE_SUPPORTED
1316 1317 1318 1319 1320
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1321
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1322 1323 1324 1325 1326
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1327 1328 1329
#endif /* PNG_WRITE_SUPPORTED */

#ifndef SINGLE_ROWBUF_ALLOC
1330
         pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1331
         png_free(read_ptr, row_buf);
1332
         row_buf = NULL;
1333
#endif /* !SINGLE_ROWBUF_ALLOC */
G
Guy Schalnat 已提交
1334 1335 1336
      }
   }

1337
#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1338
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1339
#endif
1340
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1341
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1342 1343
#endif

1344
   pngtest_debug("Reading and writing end_info data");
1345

A
Andreas Dilger 已提交
1346
   png_read_end(read_ptr, end_info_ptr);
1347
#ifdef PNG_TEXT_SUPPORTED
1348 1349 1350 1351 1352 1353
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1354
         pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1355 1356 1357 1358
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1359
#ifdef PNG_tIME_SUPPORTED
1360 1361 1362 1363 1364 1365
   {
      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);
1366
#ifdef PNG_TIME_RFC1123_SUPPORTED
1367
         /* We have to use png_memcpy instead of "=" because the string
1368 1369
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
1370 1371 1372
         png_memcpy(tIME_string,
                    png_convert_to_rfc1123(read_ptr, mod_time),
                    png_sizeof(tIME_string));
1373

1374
         tIME_string[png_sizeof(tIME_string) - 1] = '\0';
1375 1376 1377 1378
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1379
#endif
1380
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1381 1382
   {
      png_unknown_chunkp unknowns;
1383
      int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1384
         &unknowns);
1385

1386 1387
      if (num_unknowns)
      {
1388
         int i;
1389 1390
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
1391
         /* Copy the locations from the read_info_ptr.  The automatically
1392 1393 1394
          * generated locations in write_end_info_ptr are wrong because we
          * haven't written the end_info yet.
          */
1395
         for (i = 0; i < num_unknowns; i++)
1396 1397
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1398 1399
      }
   }
1400
#endif
1401
#ifdef PNG_WRITE_SUPPORTED
1402
   png_write_end(write_ptr, write_end_info_ptr);
1403
#endif
1404

1405
#ifdef PNG_EASY_ACCESS_SUPPORTED
1406
   if (verbose)
1407 1408 1409 1410
   {
      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);
1411
      fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1412
         (unsigned long)iwidth, (unsigned long)iheight);
1413 1414
   }
#endif
G
Guy Schalnat 已提交
1415

1416
   pngtest_debug("Destroying data structs");
1417
#ifdef SINGLE_ROWBUF_ALLOC
1418
   pngtest_debug("destroying row_buf for read_ptr");
1419
   png_free(read_ptr, row_buf);
1420
   row_buf = NULL;
1421
#endif /* SINGLE_ROWBUF_ALLOC */
1422
   pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
A
Andreas Dilger 已提交
1423
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1424
#ifdef PNG_WRITE_SUPPORTED
1425
   pngtest_debug("destroying write_end_info_ptr");
1426
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1427
   pngtest_debug("destroying write_ptr, write_info_ptr");
A
Andreas Dilger 已提交
1428
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1429
#endif
1430
   pngtest_debug("Destruction complete.");
G
Guy Schalnat 已提交
1431

1432 1433
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1434

1435
   pngtest_debug("Opening files for comparison");
A
Andreas Dilger 已提交
1436
   if ((fpin = fopen(inname, "rb")) == NULL)
G
Guy Schalnat 已提交
1437
   {
G
Guy Schalnat 已提交
1438
      fprintf(STDERR, "Could not find file %s\n", inname);
1439
      return (1);
G
Guy Schalnat 已提交
1440 1441
   }

A
Andreas Dilger 已提交
1442
   if ((fpout = fopen(outname, "rb")) == NULL)
G
Guy Schalnat 已提交
1443
   {
G
Guy Schalnat 已提交
1444
      fprintf(STDERR, "Could not find file %s\n", outname);
1445
      FCLOSE(fpin);
1446
      return (1);
G
Guy Schalnat 已提交
1447
   }
A
Andreas Dilger 已提交
1448

1449
   for (;;)
G
Guy Schalnat 已提交
1450
   {
A
Andreas Dilger 已提交
1451
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1452

1453 1454
         num_in = fread(inbuf, 1, 1, fpin);
         num_out = fread(outbuf, 1, 1, fpout);
G
Guy Schalnat 已提交
1455 1456 1457

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

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

1474 1475
         FCLOSE(fpin);
         FCLOSE(fpout);
1476
         return (0);
G
Guy Schalnat 已提交
1477 1478 1479 1480 1481
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1482
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1483
      {
1484
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1485

1486
         if (wrote_question == 0)
1487 1488
         {
            fprintf(STDERR,
1489
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1490
                 inname, PNG_ZBUF_SIZE);
1491
            fprintf(STDERR,
1492
              "\n   filtering heuristic (libpng default), compression");
1493
            fprintf(STDERR,
1494
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1495
              ZLIB_VERSION);
1496
            wrote_question = 1;
1497
         }
1498

1499 1500
         FCLOSE(fpin);
         FCLOSE(fpout);
1501
         return (0);
G
Guy Schalnat 已提交
1502 1503 1504
      }
   }

1505 1506
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1507

1508
   return (0);
G
Guy Schalnat 已提交
1509
}
G
Guy Schalnat 已提交
1510

1511
/* Input and output filenames */
1512
#ifdef RISCOS
1513 1514
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1515
#else
1516 1517
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1518 1519 1520 1521 1522 1523 1524 1525
#endif

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

1526
   fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1527
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1528
   fprintf(STDERR, "%s", png_get_copyright(NULL));
1529
   /* Show the version of libpng used in building the library */
1530 1531
   fprintf(STDERR, " library (%lu):%s",
      (unsigned long)png_access_version_number(),
1532
      png_get_header_version(NULL));
1533

1534
   /* Show the version of libpng used in building the application */
1535
   fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1536
      PNG_HEADER_VERSION_STRING);
1537 1538

   /* Do some consistency checking on the memory allocation settings, I'm
1539 1540 1541 1542
    * 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
    */
1543
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1544
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1545
#endif
1546
   /* I think the following can happen. */
1547
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1548
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1549
#endif
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561

   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)
   {
1562
      if (strcmp(argv[1], "-m") == 0)
1563
      {
1564
         multiple = 1;
1565 1566
         status_dots_requested = 0;
      }
1567

1568 1569 1570 1571 1572
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1573
         status_dots_requested = 1;
1574
      }
1575

1576 1577 1578
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1579
         status_dots_requested = 1;
1580 1581
         inname = argv[2];
      }
1582

1583
      else
1584
      {
1585
         inname = argv[1];
1586 1587
         status_dots_requested = 0;
      }
1588 1589
   }

1590 1591
   if (!multiple && argc == 3 + verbose)
     outname = argv[2 + verbose];
1592

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

   if (multiple)
   {
      int i;
1608
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1609 1610
      int allocation_now = current_allocation;
#endif
1611
      for (i=2; i<argc; ++i)
1612
      {
1613
         int kerror;
1614
         fprintf(STDERR, "\n Testing %s:", argv[i]);
1615
         kerror = test_one_file(argv[i], outname);
1616
         if (kerror == 0)
1617
         {
1618 1619 1620
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
            int k;
#endif
1621
#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1622
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1623
               (unsigned long)zero_samples);
1624
#else
1625
            fprintf(STDERR, " PASS\n");
1626
#endif
1627
#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1628 1629
            for (k = 0; k<256; k++)
               if (filters_used[k])
1630
                  fprintf(STDERR, " Filter %d was used %lu times\n",
1631
                     k, (unsigned long)filters_used[k]);
1632
#endif
1633
#ifdef PNG_TIME_RFC1123_SUPPORTED
1634 1635
         if (tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n", tIME_string);
1636

1637 1638 1639
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
1640

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

1651 1652
         if (current_allocation != 0)
         {
1653 1654 1655 1656
            memory_infop pinfo = pinformation;

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

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

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

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

1695
         if (i == 0 || verbose == 1 || ierror != 0)
1696
            fprintf(STDERR, "\n Testing %s:", inname);
1697

1698
         kerror = test_one_file(inname, outname);
1699

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

1726 1727
         else
         {
1728
            if (verbose == 0 && i != 2)
1729
               fprintf(STDERR, "\n Testing %s:", inname);
1730

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

1739 1740
         if (current_allocation != 0)
         {
1741
             memory_infop pinfo = pinformation;
1742

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

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

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

1781
   if (ierror == 0)
1782
      fprintf(STDERR, " libpng passes test\n");
1783

1784
   else
1785
      fprintf(STDERR, " libpng FAILS test\n");
1786

1787
   return (int)(ierror != 0);
1788
}
1789

1790
/* Generate a compiler error if there is an old png.h in the search path. */
1791
typedef png_libpng_version_1_5_3beta02 Your_png_h_is_not_version_1_5_3beta02;