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

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

31 32 33 34 35 36 37
#if defined(_WIN32_WCE)
#  if _WIN32_WCE < 211
     __error__ (f|w)printf functions are not supported on old WindowsCE.;
#  endif
#  include <windows.h>
#  include <stdlib.h>
#  define READFILE(file, data, length, check) \
38 39 40
     if (ReadFile(file, data, length, &check,NULL)) check = 0
#  define WRITEFILE(file, data, length, check)) \
     if (WriteFile(file, data, length, &check, NULL)) check = 0
41 42 43 44 45 46 47 48
#  define FCLOSE(file) CloseHandle(file)
#else
#  include <stdio.h>
#  include <stdlib.h>
#  include <assert.h>
#  define READFILE(file, data, length, check) \
     check=(png_size_t)fread(data,(png_size_t)1,length,file)
#  define WRITEFILE(file, data, length, check) \
49
     check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
50 51
#  define FCLOSE(file) fclose(file)
#endif
A
Andreas Dilger 已提交
52

53
#if defined(PNG_NO_STDIO)
54 55 56 57 58
#  if defined(_WIN32_WCE)
     typedef HANDLE                png_FILE_p;
#  else
     typedef FILE                * png_FILE_p;
#  endif
59 60
#endif

A
Andreas Dilger 已提交
61 62
/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
#ifndef PNG_DEBUG
63 64 65 66
#  define PNG_DEBUG 0
#endif

#if !PNG_DEBUG
67
#  define SINGLE_ROWBUF_ALLOC  /* makes buffer overruns easier to nail */
68
#endif
A
Andreas Dilger 已提交
69

70 71 72 73
/* Turn on CPU timing
#define PNGTEST_TIMING
*/

74 75 76 77
#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
#undef PNGTEST_TIMING
#endif

78 79 80 81 82
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
#include <time.h>
#endif

G
Guy Schalnat 已提交
83 84
#include "png.h"

85 86 87 88 89
/* 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

90 91
#ifdef PNGTEST_TIMING
static float t_start, t_stop, t_decode, t_encode, t_misc;
92
#if !defined(PNG_tIME_SUPPORTED)
93 94 95 96
#include <time.h>
#endif
#endif

97 98
#if defined(PNG_TIME_RFC1123_SUPPORTED)
static int tIME_chunk_present=0;
99
static char tIME_string[30] = "no tIME chunk present in file";
100
#endif
101

102 103
static int verbose = 0;

104
int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
105

G
Guy Schalnat 已提交
106 107 108 109 110
#ifdef __TURBOC__
#include <mem.h>
#endif

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

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

119 120
void
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
121 122
void
read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
123
{
124
    if(png_ptr == NULL || row_number > PNG_MAX_UINT) return;
125 126 127 128
    if(status_pass != pass)
    {
       fprintf(stdout,"\n Pass %d: ",pass);
       status_pass = pass;
129
       status_dots = 31;
130 131 132 133 134 135 136 137 138
    }
    status_dots--;
    if(status_dots == 0)
    {
       fprintf(stdout, "\n         ");
       status_dots=30;
    }
    fprintf(stdout, "r");
}
139

140 141
void
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
142 143
void
write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
144
{
145
    if(png_ptr == NULL || row_number > PNG_MAX_UINT || pass > 7) return;
146 147 148 149
    fprintf(stdout, "w");
}


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

165
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
166
/* example of using user transform callback (we don't transform anything,
167
   but merely count the zero samples) */
168

169
static png_uint_32 zero_samples;
170

171 172
void
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
173
void
174
count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
175 176
{
   png_bytep dp = data;
177
   if(png_ptr == NULL)return;
178 179 180 181 182 183 184 185 186 187

   /* contents of row_info:
    *  png_uint_32 width      width of row
    *  png_uint_32 rowbytes   number of bytes in row
    *  png_byte color_type    color type of pixels
    *  png_byte bit_depth     bit depth of samples
    *  png_byte channels      number of channels (1-4)
    *  png_byte pixel_depth   bits per pixel (depth*channels)
    */

188

189
    /* counts the number of zero samples (or zero pixels if color_type is 3 */
190 191 192 193

    if(row_info->color_type == 0 || row_info->color_type == 3)
    {
       int pos=0;
194 195
       png_uint_32 n, nstop;
       for (n=0, nstop=row_info->width; n<nstop; n++)
196 197
       {
          if(row_info->bit_depth == 1)
198
          {
199
             if(((*dp << pos++ ) & 0x80) == 0) zero_samples++;
200 201
             if(pos == 8)
             {
202
                pos = 0;
203 204
                dp++;
             }
205
          }
206
          if(row_info->bit_depth == 2)
207
          {
208
             if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
209 210
             if(pos == 8)
             {
211
                pos = 0;
212 213
                dp++;
             }
214
          }
215
          if(row_info->bit_depth == 4)
216
          {
217
             if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
218 219
             if(pos == 8)
             {
220
                pos = 0;
221 222
                dp++;
             }
223
          }
224
          if(row_info->bit_depth == 8)
225
             if(*dp++ == 0) zero_samples++;
226 227
          if(row_info->bit_depth == 16)
          {
228
             if((*dp | *(dp+1)) == 0) zero_samples++;
229 230 231 232 233 234
             dp+=2;
          }
       }
    }
    else /* other color types */
    {
235
       png_uint_32 n, nstop;
236 237 238 239
       int channel;
       int color_channels = row_info->channels;
       if(row_info->color_type > 3)color_channels--;

240
       for (n=0, nstop=row_info->width; n<nstop; n++)
241 242 243 244
       {
          for (channel = 0; channel < color_channels; channel++)
          {
             if(row_info->bit_depth == 8)
245
                if(*dp++ == 0) zero_samples++;
246 247
             if(row_info->bit_depth == 16)
             {
248
                if((*dp | *(dp+1)) == 0) zero_samples++;
249 250 251 252 253 254 255 256 257 258 259
                dp+=2;
             }
          }
          if(row_info->color_type > 3)
          {
             dp++;
             if(row_info->bit_depth == 16)dp++;
          }
       }
    }
}
260
#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
261

262
static int wrote_question = 0;
263

264
#if defined(PNG_NO_STDIO)
265 266 267
/* START of code to validate stdio-free compilation */
/* These copies of the default read/write functions come from pngrio.c and */
/* pngwio.c.  They allow "don't include stdio" testing of the library. */
268
/* This is the function that does the actual reading of data.  If you are
269 270 271
   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. */
272

273 274
#ifndef USE_FAR_KEYWORD
static void
275
pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
276 277 278 279 280 281
{
   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.
    */
282
   READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
283 284 285

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

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

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

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

339
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
340
static void
341
pngtest_flush(png_structp png_ptr)
342
{
343 344 345
#if !defined(_WIN32_WCE)
   png_FILE_p io_ptr;
   io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
346 347
   if (io_ptr != NULL)
      fflush(io_ptr);
348
#endif
349 350
}
#endif
G
Guy Schalnat 已提交
351

352
/* This is the function that does the actual writing of data.  If you are
353 354 355 356 357
   not writing to a standard C stream, you should create a replacement
   write_data function and use it at run time with png_set_write_fn(), rather
   than changing the library. */
#ifndef USE_FAR_KEYWORD
static void
358
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
359 360 361
{
   png_uint_32 check;

362
   WRITEFILE((png_FILE_p)png_ptr->io_ptr,  data, length, check);
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
   if (check != length)
   {
      png_error(png_ptr, "Write Error");
   }
}
#else
/* this is the model-independent version. Since the standard I/O library
   can't handle far buffers in the medium and small models, we have to copy
   the data.
*/

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

static void
378
pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
379 380 381
{
   png_uint_32 check;
   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
382
   png_FILE_p io_ptr;
383 384 385

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

417
#endif /* USE_FAR_KEYWORD */
418 419 420 421 422 423 424

/* 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
425
pngtest_warning(png_structp png_ptr, png_const_charp message)
426 427 428 429 430 431 432 433 434 435 436 437 438
{
   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
439
pngtest_error(png_structp png_ptr, png_const_charp message)
440
{
441
   pngtest_warning(png_ptr, message);
442 443
   /* We can return because png_error calls the default handler, which is
    * actually OK in this case. */
444
}
445
#endif /* PNG_NO_STDIO */
446 447
/* END of code to validate stdio-free compilation */

448
/* START of code to validate memory allocation and deallocation */
449
#ifdef PNG_USER_MEM_SUPPORTED
450 451 452 453 454 455 456 457 458

/* Allocate memory.  For reasonable files, size should never exceed
   64K.  However, zlib may allocate more then 64K if you don't tell
   it not to.  See zconf.h and png.h for more information.  zlib does
   need to allocate exactly 64K, so whatever you call here must
   have the ability to do that.

   This piece of code can be compiled to validate max 64K allocations
   by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
459 460
typedef struct memory_information
{
461
   png_uint_32               size;
462
   png_voidp                 pointer;
463 464 465 466 467 468 469
   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;
470 471
static int total_allocation = 0;
static int num_allocations = 0;
472

473 474
png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
475 476

png_voidp
477 478
png_debug_malloc(png_structp png_ptr, png_uint_32 size)
{
479 480 481 482

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

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

   /* This calls the library allocator twice, once to get the requested
      buffer and once to get a new free list entry. */
   {
489
      memory_infop pinfo = (memory_infop)png_malloc_default(png_ptr,
490
         (png_uint_32)sizeof *pinfo);
491 492
      pinfo->size = size;
      current_allocation += size;
493 494
      total_allocation += size;
      num_allocations ++;
495 496
      if (current_allocation > maximum_allocation)
         maximum_allocation = current_allocation;
497
      pinfo->pointer = (png_voidp)png_malloc_default(png_ptr, size);
498 499 500 501
      pinfo->next = pinformation;
      pinformation = pinfo;
      /* Make sure the caller isn't assuming zeroed memory. */
      png_memset(pinfo->pointer, 0xdd, pinfo->size);
502 503
#if PNG_DEBUG
      if(verbose)
504
         printf("png_malloc %lu bytes at %x\n",size,pinfo->pointer);
505
#endif
506
      assert(pinfo->size != 12345678);
507
      return (png_voidp)(pinfo->pointer);
508 509 510 511 512
   }
}

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

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

564
/* Test one file */
565 566
int
test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
G
Guy Schalnat 已提交
567
{
568 569
   static png_FILE_p fpin;
   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
570 571 572 573 574 575 576 577 578 579 580
   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 已提交
581
   png_bytep row_buf;
G
Guy Schalnat 已提交
582
   png_uint_32 y;
A
Andreas Dilger 已提交
583 584 585
   png_uint_32 width, height;
   int num_pass, pass;
   int bit_depth, color_type;
586
#ifdef PNG_SETJMP_SUPPORTED
A
Andreas Dilger 已提交
587
#ifdef USE_FAR_KEYWORD
588
   jmp_buf jmpbuf;
589
#endif
590
#endif
591

592 593 594
#if defined(_WIN32_WCE)
   TCHAR path[MAX_PATH];
#endif
595
   char inbuf[256], outbuf[256];
G
Guy Schalnat 已提交
596

597
   row_buf = NULL;
G
Guy Schalnat 已提交
598

599 600 601 602
#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
   if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
A
Andreas Dilger 已提交
603
   if ((fpin = fopen(inname, "rb")) == NULL)
604
#endif
G
Guy Schalnat 已提交
605 606
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
607
      return (1);
G
Guy Schalnat 已提交
608 609
   }

610 611 612 613
#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
   if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
A
Andreas Dilger 已提交
614
   if ((fpout = fopen(outname, "wb")) == NULL)
615
#endif
G
Guy Schalnat 已提交
616
   {
G
Guy Schalnat 已提交
617
      fprintf(STDERR, "Could not open output file %s\n", outname);
618
      FCLOSE(fpin);
619
      return (1);
G
Guy Schalnat 已提交
620 621
   }

A
Andreas Dilger 已提交
622
   png_debug(0, "Allocating read and write structures\n");
623
#ifdef PNG_USER_MEM_SUPPORTED
624 625
   read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
626 627
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
628 629
   read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL);
630
#endif
631
#if defined(PNG_NO_STDIO)
632 633
   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
634
#endif
635
#ifdef PNG_WRITE_SUPPORTED
636
#ifdef PNG_USER_MEM_SUPPORTED
637 638
   write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
639 640
      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
#else
641 642
   write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
      png_error_ptr_NULL, png_error_ptr_NULL);
643
#endif
644
#if defined(PNG_NO_STDIO)
645 646
   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
       pngtest_warning);
647
#endif
648
#endif
A
Andreas Dilger 已提交
649 650
   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
   read_info_ptr = png_create_info_struct(read_ptr);
651
   end_info_ptr = png_create_info_struct(read_ptr);
652 653
#ifdef PNG_WRITE_SUPPORTED
   write_info_ptr = png_create_info_struct(write_ptr);
654
   write_end_info_ptr = png_create_info_struct(write_ptr);
655
#endif
G
Guy Schalnat 已提交
656

657
#ifdef PNG_SETJMP_SUPPORTED
658
   png_debug(0, "Setting jmpbuf for read struct\n");
A
Andreas Dilger 已提交
659
#ifdef USE_FAR_KEYWORD
660
   if (setjmp(jmpbuf))
A
Andreas Dilger 已提交
661
#else
662
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
663
#endif
G
Guy Schalnat 已提交
664
   {
665
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
666 667
      if (row_buf)
         png_free(read_ptr, row_buf);
A
Andreas Dilger 已提交
668
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
669
#ifdef PNG_WRITE_SUPPORTED
670
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
671
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
672
#endif
673 674
      FCLOSE(fpin);
      FCLOSE(fpout);
675
      return (1);
G
Guy Schalnat 已提交
676
   }
677
#ifdef USE_FAR_KEYWORD
678
   png_memcpy(png_jmpbuf(read_ptr),jmpbuf,sizeof(jmp_buf));
679
#endif
A
Andreas Dilger 已提交
680

681
#ifdef PNG_WRITE_SUPPORTED
682
   png_debug(0, "Setting jmpbuf for write struct\n");
A
Andreas Dilger 已提交
683
#ifdef USE_FAR_KEYWORD
684
   if (setjmp(jmpbuf))
A
Andreas Dilger 已提交
685
#else
686
   if (setjmp(png_jmpbuf(write_ptr)))
A
Andreas Dilger 已提交
687
#endif
G
Guy Schalnat 已提交
688
   {
689
      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
A
Andreas Dilger 已提交
690
      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
691
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
692
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
693
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
694
#endif
695 696
      FCLOSE(fpin);
      FCLOSE(fpout);
697
      return (1);
G
Guy Schalnat 已提交
698
   }
A
Andreas Dilger 已提交
699
#ifdef USE_FAR_KEYWORD
700
   png_memcpy(png_jmpbuf(write_ptr),jmpbuf,sizeof(jmp_buf));
701
#endif
702
#endif
A
Andreas Dilger 已提交
703
#endif
704

A
Andreas Dilger 已提交
705
   png_debug(0, "Initializing input and output streams\n");
706
#if !defined(PNG_NO_STDIO)
G
Guy Schalnat 已提交
707
   png_init_io(read_ptr, fpin);
708
#  ifdef PNG_WRITE_SUPPORTED
G
Guy Schalnat 已提交
709
   png_init_io(write_ptr, fpout);
710
#  endif
711
#else
712
   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
713
#  ifdef PNG_WRITE_SUPPORTED
714
   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
715
#    if defined(PNG_WRITE_FLUSH_SUPPORTED)
716
      pngtest_flush);
717
#    else
718
      NULL);
719 720
#    endif
#  endif
721 722 723
#endif
   if(status_dots_requested == 1)
   {
724
#ifdef PNG_WRITE_SUPPORTED
725
      png_set_write_status_fn(write_ptr, write_row_callback);
726
#endif
727 728 729 730
      png_set_read_status_fn(read_ptr, read_row_callback);
   }
   else
   {
731
#ifdef PNG_WRITE_SUPPORTED
732
      png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL);
733
#endif
734
      png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL);
735 736
   }

737 738 739 740 741 742 743 744 745 746 747 748
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
   {
     int i;
     for(i=0; i<256; i++)
        filters_used[i]=0;
     png_set_read_user_transform_fn(read_ptr, count_filters);
   }
#endif
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
   zero_samples=0;
   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
#endif
G
Guy Schalnat 已提交
749

750 751 752
#define HANDLE_CHUNK_IF_SAFE      2
#define HANDLE_CHUNK_ALWAYS       3
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
753
   png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS,
754
      png_bytep_NULL, 0);
755 756
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
757
   png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE,
758
      png_bytep_NULL, 0);
759 760
#endif

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

A
Andreas Dilger 已提交
764 765 766
   png_debug(0, "Transferring info struct\n");
   {
      int interlace_type, compression_type, filter_type;
G
Guy Schalnat 已提交
767

A
Andreas Dilger 已提交
768 769 770 771
      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,
772
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
773
            color_type, interlace_type, compression_type, filter_type);
774 775 776
#else
            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
#endif
A
Andreas Dilger 已提交
777 778
      }
   }
779
#if defined(PNG_FIXED_POINT_SUPPORTED)
780
#if defined(PNG_cHRM_SUPPORTED)
G
Guy Schalnat 已提交
781
   {
782
      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
783 784 785
         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 已提交
786
      {
787 788
         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 已提交
789
      }
G
Guy Schalnat 已提交
790
   }
A
Andreas Dilger 已提交
791
#endif
792
#if defined(PNG_gAMA_SUPPORTED)
A
Andreas Dilger 已提交
793
   {
794
      png_fixed_point gamma;
G
Guy Schalnat 已提交
795

796
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
A
Andreas Dilger 已提交
797
      {
798
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
799 800 801
      }
   }
#endif
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
#else /* Use floating point versions */
#if defined(PNG_FLOATING_POINT_SUPPORTED)
#if defined(PNG_cHRM_SUPPORTED)
   {
      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
         blue_y;
      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
         &red_y, &green_x, &green_y, &blue_x, &blue_y))
      {
         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
            red_y, green_x, green_y, blue_x, blue_y);
      }
   }
#endif
#if defined(PNG_gAMA_SUPPORTED)
   {
      double gamma;

      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
      {
         png_set_gAMA(write_ptr, write_info_ptr, gamma);
      }
   }
#endif
#endif /* floating point */
#endif /* fixed point */
828
#if defined(PNG_iCCP_SUPPORTED)
G
Guy Schalnat 已提交
829
   {
830 831
      png_charp name;
      png_charp profile;
832
      png_uint_32 proflen;
833
      int compression_type;
A
Andreas Dilger 已提交
834

835 836
      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
                      &profile, &proflen))
A
Andreas Dilger 已提交
837
      {
838 839
         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
                      profile, proflen);
A
Andreas Dilger 已提交
840
      }
G
Guy Schalnat 已提交
841
   }
842
#endif
843
#if defined(PNG_sRGB_SUPPORTED)
844
   {
845
      int intent;
846 847 848 849 850 851

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
      {
         png_set_sRGB(write_ptr, write_info_ptr, intent);
      }
   }
A
Andreas Dilger 已提交
852
#endif
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
   {
      png_colorp palette;
      int num_palette;

      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
      {
         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
      }
   }
#if defined(PNG_bKGD_SUPPORTED)
   {
      png_color_16p background;

      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
      {
         png_set_bKGD(write_ptr, write_info_ptr, background);
      }
   }
#endif
#if defined(PNG_hIST_SUPPORTED)
G
Guy Schalnat 已提交
873
   {
A
Andreas Dilger 已提交
874 875 876 877 878 879
      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 已提交
880
   }
A
Andreas Dilger 已提交
881
#endif
882
#if defined(PNG_oFFs_SUPPORTED)
A
Andreas Dilger 已提交
883
   {
884
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
885
      int unit_type;
G
Guy Schalnat 已提交
886

A
Andreas Dilger 已提交
887 888 889 890 891 892
      if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
      {
         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
      }
   }
#endif
893
#if defined(PNG_pCAL_SUPPORTED)
A
Andreas Dilger 已提交
894 895 896 897 898 899 900 901 902 903 904 905 906 907
   {
      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
908
#if defined(PNG_pHYs_SUPPORTED)
A
Andreas Dilger 已提交
909 910 911 912 913 914 915 916 917 918
   {
      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
919
#if defined(PNG_sBIT_SUPPORTED)
A
Andreas Dilger 已提交
920
   {
921
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
922

923
      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
A
Andreas Dilger 已提交
924
      {
925
         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
A
Andreas Dilger 已提交
926 927
      }
   }
928 929 930
#endif
#if defined(PNG_sCAL_SUPPORTED)
#ifdef PNG_FLOATING_POINT_SUPPORTED
G
Guy Schalnat 已提交
931
   {
932
      int unit;
933
      double scal_width, scal_height;
A
Andreas Dilger 已提交
934

935 936
      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
         &scal_height))
G
Guy Schalnat 已提交
937
      {
938
         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
939 940 941
      }
   }
#else
942
#ifdef PNG_FIXED_POINT_SUPPORTED
943
   {
944
      int unit;
945
      png_charp scal_width, scal_height;
946

947 948
      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
          &scal_height))
949
      {
950
         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
A
Andreas Dilger 已提交
951 952
      }
   }
G
Guy Schalnat 已提交
953
#endif
954 955
#endif
#endif
956
#if defined(PNG_TEXT_SUPPORTED)
A
Andreas Dilger 已提交
957 958 959 960 961 962
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
963
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
A
Andreas Dilger 已提交
964 965 966 967
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
968
#if defined(PNG_tIME_SUPPORTED)
A
Andreas Dilger 已提交
969 970 971 972 973 974
   {
      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);
975 976 977 978 979 980 981
#if defined(PNG_TIME_RFC1123_SUPPORTED)
         /* we have to use png_strcpy instead of "=" because the string
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
         png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
982
      }
A
Andreas Dilger 已提交
983 984
   }
#endif
985
#if defined(PNG_tRNS_SUPPORTED)
A
Andreas Dilger 已提交
986 987 988 989 990 991 992 993 994 995 996 997 998
   {
      png_bytep trans;
      int num_trans;
      png_color_16p trans_values;

      if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
         &trans_values))
      {
         png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
            trans_values);
      }
   }
#endif
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   {
      png_unknown_chunkp unknowns;
      int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
         &unknowns);
      if (num_unknowns)
      {
         png_size_t i;
         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
           num_unknowns);
         /* copy the locations from the read_info_ptr.  The automatically
            generated locations in write_info_ptr are wrong because we
            haven't written anything yet */
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1013 1014
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1015 1016 1017
      }
   }
#endif
A
Andreas Dilger 已提交
1018

1019
#ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1020
   png_debug(0, "\nWriting info struct\n");
1021 1022 1023 1024

/* If we wanted, we could write info in two steps:
   png_write_info_before_PLTE(write_ptr, write_info_ptr);
 */
A
Andreas Dilger 已提交
1025
   png_write_info(write_ptr, write_info_ptr);
1026
#endif
A
Andreas Dilger 已提交
1027

1028 1029
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(0, "\nAllocating row buffer...");
1030
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1031
      png_get_rowbytes(read_ptr, read_info_ptr));
1032 1033
   png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
#endif /* SINGLE_ROWBUF_ALLOC */
1034
   png_debug(0, "Writing row data\n");
A
Andreas Dilger 已提交
1035

1036 1037
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1038
   num_pass = png_set_interlace_handling(read_ptr);
1039
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1040
   png_set_interlace_handling(write_ptr);
1041
#  endif
1042 1043 1044
#else
   num_pass=1;
#endif
A
Andreas Dilger 已提交
1045

1046 1047 1048 1049 1050
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1051 1052
   for (pass = 0; pass < num_pass; pass++)
   {
1053
      png_debug1(0, "Writing row data for pass %d\n",pass);
A
Andreas Dilger 已提交
1054 1055
      for (y = 0; y < height; y++)
      {
1056 1057 1058 1059 1060 1061 1062
#ifndef SINGLE_ROWBUF_ALLOC
         png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y);
         row_buf = (png_bytep)png_malloc(read_ptr,
            png_get_rowbytes(read_ptr, read_info_ptr));
         png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
            png_get_rowbytes(read_ptr, read_info_ptr));
#endif /* !SINGLE_ROWBUF_ALLOC */
1063
         png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1);
1064 1065

#ifdef PNG_WRITE_SUPPORTED
1066 1067 1068 1069 1070
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1071
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1072 1073 1074 1075 1076
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1077 1078 1079 1080 1081 1082
#endif /* PNG_WRITE_SUPPORTED */

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

1086
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1087
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1088 1089
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1090
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1091 1092
#endif

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

A
Andreas Dilger 已提交
1095
   png_read_end(read_ptr, end_info_ptr);
1096
#if defined(PNG_TEXT_SUPPORTED)
1097 1098 1099 1100 1101 1102
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1103
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1104 1105 1106 1107
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1108
#if defined(PNG_tIME_SUPPORTED)
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
   {
      png_timep mod_time;

      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
      {
         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
#if defined(PNG_TIME_RFC1123_SUPPORTED)
         /* we have to use png_strcpy instead of "=" because the string
            pointed to by png_convert_to_rfc1123() gets free'ed before
            we use it */
         png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
         tIME_chunk_present++;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
      }
   }
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   {
      png_unknown_chunkp unknowns;
      int num_unknowns;
      num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
         &unknowns);
      if (num_unknowns)
      {
         png_size_t i;
         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
           num_unknowns);
         /* copy the locations from the read_info_ptr.  The automatically
            generated locations in write_end_info_ptr are wrong because we
            haven't written the end_info yet */
         for (i = 0; i < (png_size_t)num_unknowns; i++)
1140 1141
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1142 1143
      }
   }
1144
#endif
1145
#ifdef PNG_WRITE_SUPPORTED
1146
   png_write_end(write_ptr, write_end_info_ptr);
1147
#endif
1148

1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
#ifdef PNG_EASY_ACCESS_SUPPORTED
   if(verbose)
   {
      png_uint_32 iwidth, iheight;
      iwidth = png_get_image_width(write_ptr, write_info_ptr);
      iheight = png_get_image_height(write_ptr, write_info_ptr);
      fprintf(STDERR, "Image width = %lu, height = %lu\n",
         iwidth, iheight);
   }
#endif
G
Guy Schalnat 已提交
1159

A
Andreas Dilger 已提交
1160
   png_debug(0, "Destroying data structs\n");
1161 1162
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(1, "destroying row_buf for read_ptr\n");
1163
   png_free(read_ptr, row_buf);
1164
   row_buf=NULL;
1165 1166
#endif /* SINGLE_ROWBUF_ALLOC */
   png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
A
Andreas Dilger 已提交
1167
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1168 1169
#ifdef PNG_WRITE_SUPPORTED
   png_debug(1, "destroying write_end_info_ptr\n");
1170
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1171
   png_debug(1, "destroying write_ptr, write_info_ptr\n");
A
Andreas Dilger 已提交
1172
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1173 1174
#endif
   png_debug(0, "Destruction complete.\n");
G
Guy Schalnat 已提交
1175

1176 1177
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1178

A
Andreas Dilger 已提交
1179
   png_debug(0, "Opening files for comparison\n");
1180 1181 1182 1183
#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
   if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
A
Andreas Dilger 已提交
1184
   if ((fpin = fopen(inname, "rb")) == NULL)
1185
#endif
G
Guy Schalnat 已提交
1186
   {
G
Guy Schalnat 已提交
1187
      fprintf(STDERR, "Could not find file %s\n", inname);
1188
      return (1);
G
Guy Schalnat 已提交
1189 1190
   }

1191 1192 1193 1194
#if defined(_WIN32_WCE)
   MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
   if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
#else
A
Andreas Dilger 已提交
1195
   if ((fpout = fopen(outname, "rb")) == NULL)
1196
#endif
G
Guy Schalnat 已提交
1197
   {
G
Guy Schalnat 已提交
1198
      fprintf(STDERR, "Could not find file %s\n", outname);
1199
      FCLOSE(fpin);
1200
      return (1);
G
Guy Schalnat 已提交
1201
   }
A
Andreas Dilger 已提交
1202

1203
   for(;;)
G
Guy Schalnat 已提交
1204
   {
A
Andreas Dilger 已提交
1205
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1206

1207 1208
      READFILE(fpin, inbuf, 1, num_in);
      READFILE(fpout, outbuf, 1, num_out);
G
Guy Schalnat 已提交
1209 1210 1211

      if (num_in != num_out)
      {
1212
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1213
                 inname, outname);
1214 1215 1216
         if(wrote_question == 0)
         {
            fprintf(STDERR,
1217 1218
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
              inname,PNG_ZBUF_SIZE);
1219
            fprintf(STDERR,
1220
              "\n   filtering heuristic (libpng default), compression");
1221
            fprintf(STDERR,
1222
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1223 1224 1225
              ZLIB_VERSION);
            wrote_question=1;
         }
1226 1227
         FCLOSE(fpin);
         FCLOSE(fpout);
1228
         return (0);
G
Guy Schalnat 已提交
1229 1230 1231 1232 1233
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1234
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1235
      {
1236
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1237 1238 1239
         if(wrote_question == 0)
         {
            fprintf(STDERR,
1240 1241
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
                 inname,PNG_ZBUF_SIZE);
1242
            fprintf(STDERR,
1243
              "\n   filtering heuristic (libpng default), compression");
1244
            fprintf(STDERR,
1245
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1246 1247 1248
              ZLIB_VERSION);
            wrote_question=1;
         }
1249 1250
         FCLOSE(fpin);
         FCLOSE(fpout);
1251
         return (0);
G
Guy Schalnat 已提交
1252 1253 1254
      }
   }

1255 1256
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1257

1258
   return (0);
G
Guy Schalnat 已提交
1259
}
G
Guy Schalnat 已提交
1260

1261 1262
/* input and output filenames */
#ifdef RISCOS
1263 1264
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1265
#else
1266 1267
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1268 1269 1270 1271 1272 1273 1274 1275 1276
#endif

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

   fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1277
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1278
   fprintf(STDERR,"%s",png_get_copyright(NULL));
1279
   /* Show the version of libpng used in building the library */
1280 1281
   fprintf(STDERR," library (%lu):%s", png_access_version_number(),
      png_get_header_version(NULL));
1282
   /* Show the version of libpng used in building the application */
1283
   fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1284
      PNG_HEADER_VERSION_STRING);
1285
   fprintf(STDERR," sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
1286
                    (long)sizeof(png_struct), (long)sizeof(png_info));
1287 1288 1289 1290 1291

   /* Do some consistency checking on the memory allocation settings, I'm
      not sure this matters, but it is nice to know, the first of these
      tests should be impossible because of the way the macros are set
      in pngconf.h */
1292
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1293
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1294
#endif
1295
   /* I think the following can happen. */
1296
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1297
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1298
#endif
1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310

   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)
   {
1311
      if (strcmp(argv[1], "-m") == 0)
1312
      {
1313
         multiple = 1;
1314 1315
         status_dots_requested = 0;
      }
1316 1317 1318 1319 1320
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1321
         status_dots_requested = 1;
1322 1323 1324 1325
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1326
         status_dots_requested = 1;
1327 1328 1329
         inname = argv[2];
      }
      else
1330
      {
1331
         inname = argv[1];
1332 1333
         status_dots_requested = 0;
      }
1334 1335
   }

1336 1337
   if (!multiple && argc == 3+verbose)
     outname = argv[2+verbose];
1338

1339
   if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
1340
   {
1341 1342
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1343
        argv[0], argv[0]);
1344 1345 1346 1347
     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);
1348 1349 1350 1351 1352 1353
     exit(1);
   }

   if (multiple)
   {
      int i;
1354
#ifdef PNG_USER_MEM_SUPPORTED
1355 1356
      int allocation_now = current_allocation;
#endif
1357
      for (i=2; i<argc; ++i)
1358
      {
1359 1360 1361 1362
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
         int k;
#endif
         int kerror;
1363 1364
         fprintf(STDERR, "Testing %s:",argv[i]);
         kerror = test_one_file(argv[i], outname);
1365
         if (kerror == 0)
1366
         {
1367
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1368
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1369
#else
1370
            fprintf(STDERR, " PASS\n");
1371
#endif
1372 1373 1374 1375 1376 1377
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
            for (k=0; k<256; k++)
               if(filters_used[k])
                  fprintf(STDERR, " Filter %d was used %lu times\n",
                     k,filters_used[k]);
#endif
1378 1379 1380 1381 1382 1383 1384 1385
#if defined(PNG_TIME_RFC1123_SUPPORTED)
         if(tIME_chunk_present != 0)
            fprintf(STDERR, " tIME = %s\n",tIME_string);
         tIME_chunk_present = 0;
#endif /* PNG_TIME_RFC1123_SUPPORTED */
         }
         else
         {
1386 1387
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1388 1389
         }
#ifdef PNG_USER_MEM_SUPPORTED
1390 1391 1392
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
               current_allocation-allocation_now);
1393 1394
         if (current_allocation != 0)
         {
1395 1396 1397 1398
            memory_infop pinfo = pinformation;

            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
               current_allocation);
1399 1400
            while (pinfo != NULL)
            {
1401 1402
               fprintf(STDERR, " %lu bytes at %x\n", pinfo->size, 
                 (unsigned int) pinfo->pointer);
1403
               pinfo = pinfo->next;
1404
            }
1405
         }
1406 1407
#endif
      }
1408
#ifdef PNG_USER_MEM_SUPPORTED
1409
         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1410
            current_allocation);
1411
         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1412
            maximum_allocation);
1413 1414 1415 1416
         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
            total_allocation);
         fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1417
#endif
1418 1419 1420
   }
   else
   {
1421
      int i;
1422 1423
      for (i=0; i<3; ++i)
      {
1424
         int kerror;
1425
#ifdef PNG_USER_MEM_SUPPORTED
1426 1427
         int allocation_now = current_allocation;
#endif
1428 1429
         if (i == 1) status_dots_requested = 1;
         else if(verbose == 0)status_dots_requested = 0;
1430 1431
         if (i == 0 || verbose == 1 || ierror != 0)
            fprintf(STDERR, "Testing %s:",inname);
1432
         kerror = test_one_file(inname, outname);
1433 1434
         if(kerror == 0)
         {
1435
            if(verbose == 1 || i == 2)
1436
            {
1437
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1438
                int k;
1439
#endif
1440
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1441
                fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1442 1443 1444
#else
                fprintf(STDERR, " PASS\n");
#endif
1445 1446 1447 1448 1449 1450
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
                for (k=0; k<256; k++)
                   if(filters_used[k])
                      fprintf(STDERR, " Filter %d was used %lu times\n",
                         k,filters_used[k]);
#endif
1451
#if defined(PNG_TIME_RFC1123_SUPPORTED)
1452 1453
             if(tIME_chunk_present != 0)
                fprintf(STDERR, " tIME = %s\n",tIME_string);
1454 1455
#endif /* PNG_TIME_RFC1123_SUPPORTED */
            }
1456 1457 1458 1459 1460
         }
         else
         {
            if(verbose == 0 && i != 2)
               fprintf(STDERR, "Testing %s:",inname);
1461 1462
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1463
         }
1464
#ifdef PNG_USER_MEM_SUPPORTED
1465 1466 1467
         if (allocation_now != current_allocation)
             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
               current_allocation-allocation_now);
1468 1469
         if (current_allocation != 0)
         {
1470
             memory_infop pinfo = pinformation;
1471

1472 1473
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
1474 1475
             while (pinfo != NULL)
             {
1476 1477
                fprintf(STDERR," %lu bytes at %x\n",
                   pinfo->size, (unsigned int)pinfo->pointer);
1478 1479 1480 1481
                pinfo = pinfo->next;
             }
          }
#endif
1482
       }
1483
#ifdef PNG_USER_MEM_SUPPORTED
1484
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1485
          current_allocation);
1486
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1487
          maximum_allocation);
1488 1489 1490 1491
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1492
#endif
1493 1494
   }

1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
   fprintf(STDERR," CPU time used = %.3f seconds",
      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
   fprintf(STDERR," (decoding %.3f,\n",
      t_decode/(float)CLOCKS_PER_SEC);
   fprintf(STDERR,"        encoding %.3f ,",
      t_encode/(float)CLOCKS_PER_SEC);
   fprintf(STDERR," other %.3f seconds)\n\n",
      t_misc/(float)CLOCKS_PER_SEC);
#endif

1509 1510 1511 1512
   if (ierror == 0)
      fprintf(STDERR, "libpng passes test\n");
   else
      fprintf(STDERR, "libpng FAILS test\n");
1513
   return (int)(ierror != 0);
1514
}
1515

1516
/* Generate a compiler error if there is an old png.h in the search path. */
1517
typedef version_1_2_4beta3 your_png_h_is_not_version_1_2_4beta3;