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

G
Guy Schalnat 已提交
2
/* pngtest.c - a simple test program to test libpng
3
 *
4
 * libpng 1.0.11beta1 - April 4, 2001
5
 * For conditions of distribution and use, see copyright notice in png.h
6
 * Copyright (c) 1998-2001 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 67
#  define PNG_DEBUG 0
#endif

#if !PNG_DEBUG
#  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 475 476 477 478

extern PNG_EXPORT(png_voidp,png_debug_malloc) PNGARG((png_structp png_ptr,
   png_uint_32 size));
extern PNG_EXPORT(void,png_debug_free) PNGARG((png_structp png_ptr,
   png_voidp ptr));

png_voidp
479 480
png_debug_malloc(png_structp png_ptr, png_uint_32 size)
{
481 482 483 484

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

485
   if (size == 0)
486
      return (png_voidp)(NULL);
487 488 489 490

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

/* Free a pointer.  It is removed from the list at the same time. */
void
515
png_debug_free(png_structp png_ptr, png_voidp ptr)
516 517
{
   if (png_ptr == NULL)
518
      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
519 520
   if (ptr == 0)
   {
521 522 523 524 525 526 527 528 529
#if 0 /* This happens all the time. */
      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
#endif
      return;
   }

   /* Unlink the element from the list. */
   {
      memory_infop FAR *ppinfo = &pinformation;
530 531
      for (;;)
      {
532
         memory_infop pinfo = *ppinfo;
533 534
         if (pinfo->pointer == ptr)
         {
535 536 537 538 539
            *ppinfo = pinfo->next;
            current_allocation -= pinfo->size;
            if (current_allocation < 0)
               fprintf(STDERR, "Duplicate free of memory\n");
            /* We must free the list element too, but first kill
540
               the memory that is to be freed. */
541
            png_memset(ptr, 0x55, pinfo->size);
542
            png_free_default(png_ptr, pinfo);
543
            pinfo=NULL;
544 545
            break;
         }
546 547
         if (pinfo->next == NULL)
         {
548 549 550 551 552 553 554 555
            fprintf(STDERR, "Pointer %x not found\n", ptr);
            break;
         }
         ppinfo = &pinfo->next;
      }
   }

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

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

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

599
   row_buf = (png_bytep)NULL;
G
Guy Schalnat 已提交
600

601 602 603 604
#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 已提交
605
   if ((fpin = fopen(inname, "rb")) == NULL)
606
#endif
G
Guy Schalnat 已提交
607 608
   {
      fprintf(STDERR, "Could not find input file %s\n", inname);
609
      return (1);
G
Guy Schalnat 已提交
610 611
   }

612 613 614 615
#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 已提交
616
   if ((fpout = fopen(outname, "wb")) == NULL)
617
#endif
G
Guy Schalnat 已提交
618
   {
G
Guy Schalnat 已提交
619
      fprintf(STDERR, "Could not open output file %s\n", outname);
620
      FCLOSE(fpin);
621
      return (1);
G
Guy Schalnat 已提交
622 623
   }

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

659
#ifdef PNG_SETJMP_SUPPORTED
660
   png_debug(0, "Setting jmpbuf for read struct\n");
A
Andreas Dilger 已提交
661
#ifdef USE_FAR_KEYWORD
662
   if (setjmp(jmpbuf))
A
Andreas Dilger 已提交
663
#else
664
   if (setjmp(png_jmpbuf(read_ptr)))
A
Andreas Dilger 已提交
665
#endif
G
Guy Schalnat 已提交
666
   {
667
      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
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
#endif
719 720
      NULL);
#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, NULL);
733
#endif
734 735 736
      png_set_read_status_fn(read_ptr, NULL);
   }

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 753 754 755 756 757 758
#define HANDLE_CHUNK_IF_SAFE      2
#define HANDLE_CHUNK_ALWAYS       3
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
   png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0);
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
   png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0);
#endif

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

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

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

794
      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
A
Andreas Dilger 已提交
795
      {
796
         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
A
Andreas Dilger 已提交
797 798 799
      }
   }
#endif
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
#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 */
826
#if defined(PNG_iCCP_SUPPORTED)
G
Guy Schalnat 已提交
827
   {
828 829
      png_charp name;
      png_charp profile;
830
      png_uint_32 proflen;
831
      int compression_type;
A
Andreas Dilger 已提交
832

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

      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
      {
         png_set_sRGB(write_ptr, write_info_ptr, intent);
      }
   }
A
Andreas Dilger 已提交
850
#endif
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
   {
      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 已提交
871
   {
A
Andreas Dilger 已提交
872 873 874 875 876 877
      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 已提交
878
   }
A
Andreas Dilger 已提交
879
#endif
880
#if defined(PNG_oFFs_SUPPORTED)
A
Andreas Dilger 已提交
881
   {
882
      png_int_32 offset_x, offset_y;
A
Andreas Dilger 已提交
883
      int unit_type;
G
Guy Schalnat 已提交
884

A
Andreas Dilger 已提交
885 886 887 888 889 890
      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
891
#if defined(PNG_pCAL_SUPPORTED)
A
Andreas Dilger 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905
   {
      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
906
#if defined(PNG_pHYs_SUPPORTED)
A
Andreas Dilger 已提交
907 908 909 910 911 912 913 914 915 916
   {
      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
917
#if defined(PNG_sBIT_SUPPORTED)
A
Andreas Dilger 已提交
918
   {
919
      png_color_8p sig_bit;
A
Andreas Dilger 已提交
920

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

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

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

      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
      {
961
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
A
Andreas Dilger 已提交
962 963 964 965
         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
      }
   }
#endif
966
#if defined(PNG_tIME_SUPPORTED)
A
Andreas Dilger 已提交
967 968 969 970 971 972
   {
      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);
973 974 975 976 977 978 979
#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 */
980
      }
A
Andreas Dilger 已提交
981 982
   }
#endif
983
#if defined(PNG_tRNS_SUPPORTED)
A
Andreas Dilger 已提交
984 985 986 987 988 989 990 991 992 993 994 995 996
   {
      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
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
#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++)
1011 1012
           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
             unknowns[i].location);
1013 1014 1015
      }
   }
#endif
A
Andreas Dilger 已提交
1016

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

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

1026 1027
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(0, "\nAllocating row buffer...");
1028
   row_buf = (png_bytep)png_malloc(read_ptr,
A
Andreas Dilger 已提交
1029
      png_get_rowbytes(read_ptr, read_info_ptr));
1030
   png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
A
Andreas Dilger 已提交
1031 1032 1033 1034
   if (row_buf == NULL)
   {
      fprintf(STDERR, "No memory to allocate row buffer\n");
      png_destroy_read_struct(&read_ptr, &read_info_ptr, (png_infopp)NULL);
1035
#ifdef PNG_WRITE_SUPPORTED
1036
      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
A
Andreas Dilger 已提交
1037
      png_destroy_write_struct(&write_ptr, &write_info_ptr);
1038
#endif
1039 1040
      FCLOSE(fpin);
      FCLOSE(fpout);
1041
      return (1);
A
Andreas Dilger 已提交
1042
   }
1043
#endif /* SINGLE_ROWBUF_ALLOC */
1044
   png_debug(0, "Writing row data\n");
A
Andreas Dilger 已提交
1045

1046 1047
#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
  defined(PNG_WRITE_INTERLACING_SUPPORTED)
A
Andreas Dilger 已提交
1048
   num_pass = png_set_interlace_handling(read_ptr);
1049
#  ifdef PNG_WRITE_SUPPORTED
A
Andreas Dilger 已提交
1050
   png_set_interlace_handling(write_ptr);
1051
#  endif
1052 1053 1054
#else
   num_pass=1;
#endif
A
Andreas Dilger 已提交
1055

1056 1057 1058 1059 1060
#ifdef PNGTEST_TIMING
   t_stop = (float)clock();
   t_misc += (t_stop - t_start);
   t_start = t_stop;
#endif
A
Andreas Dilger 已提交
1061 1062
   for (pass = 0; pass < num_pass; pass++)
   {
1063
      png_debug1(0, "Writing row data for pass %d\n",pass);
A
Andreas Dilger 已提交
1064 1065
      for (y = 0; y < height; y++)
      {
1066 1067 1068 1069 1070 1071 1072
#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 */
A
Andreas Dilger 已提交
1073
         png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
1074 1075

#ifdef PNG_WRITE_SUPPORTED
1076 1077 1078 1079 1080
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_decode += (t_stop - t_start);
         t_start = t_stop;
#endif
G
Guy Schalnat 已提交
1081
         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1082 1083 1084 1085 1086
#ifdef PNGTEST_TIMING
         t_stop = (float)clock();
         t_encode += (t_stop - t_start);
         t_start = t_stop;
#endif
1087 1088 1089 1090 1091 1092
#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 已提交
1093 1094 1095
      }
   }

1096
#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1097
   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1098 1099
#endif
#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1100
   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1101 1102
#endif

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

A
Andreas Dilger 已提交
1105
   png_read_end(read_ptr, end_info_ptr);
1106
#if defined(PNG_TEXT_SUPPORTED)
1107 1108 1109 1110 1111 1112
   {
      png_textp text_ptr;
      int num_text;

      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
      {
1113
         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1114 1115 1116 1117
         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
      }
   }
#endif
1118
#if defined(PNG_tIME_SUPPORTED)
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
   {
      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 */
      }
   }
1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
#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++)
1150 1151
           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
             unknowns[i].location);
1152 1153
      }
   }
1154
#endif
1155
#ifdef PNG_WRITE_SUPPORTED
1156
   png_write_end(write_ptr, write_end_info_ptr);
1157
#endif
1158

1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
#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 已提交
1169

A
Andreas Dilger 已提交
1170
   png_debug(0, "Destroying data structs\n");
1171 1172
#ifdef SINGLE_ROWBUF_ALLOC
   png_debug(1, "destroying row_buf for read_ptr\n");
1173
   png_free(read_ptr, row_buf);
1174
   row_buf=NULL;
1175 1176
#endif /* SINGLE_ROWBUF_ALLOC */
   png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
A
Andreas Dilger 已提交
1177
   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1178 1179
#ifdef PNG_WRITE_SUPPORTED
   png_debug(1, "destroying write_end_info_ptr\n");
1180
   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1181
   png_debug(1, "destroying write_ptr, write_info_ptr\n");
A
Andreas Dilger 已提交
1182
   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1183 1184
#endif
   png_debug(0, "Destruction complete.\n");
G
Guy Schalnat 已提交
1185

1186 1187
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1188

A
Andreas Dilger 已提交
1189
   png_debug(0, "Opening files for comparison\n");
1190 1191 1192 1193
#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 已提交
1194
   if ((fpin = fopen(inname, "rb")) == NULL)
1195
#endif
G
Guy Schalnat 已提交
1196
   {
G
Guy Schalnat 已提交
1197
      fprintf(STDERR, "Could not find file %s\n", inname);
1198
      return (1);
G
Guy Schalnat 已提交
1199 1200
   }

1201 1202 1203 1204
#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 已提交
1205
   if ((fpout = fopen(outname, "rb")) == NULL)
1206
#endif
G
Guy Schalnat 已提交
1207
   {
G
Guy Schalnat 已提交
1208
      fprintf(STDERR, "Could not find file %s\n", outname);
1209
      FCLOSE(fpin);
1210
      return (1);
G
Guy Schalnat 已提交
1211
   }
A
Andreas Dilger 已提交
1212

1213
   for(;;)
G
Guy Schalnat 已提交
1214
   {
A
Andreas Dilger 已提交
1215
      png_size_t num_in, num_out;
G
Guy Schalnat 已提交
1216

1217 1218
      READFILE(fpin, inbuf, 1, num_in);
      READFILE(fpout, outbuf, 1, num_out);
G
Guy Schalnat 已提交
1219 1220 1221

      if (num_in != num_out)
      {
1222
         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
G
Guy Schalnat 已提交
1223
                 inname, outname);
1224 1225 1226
         if(wrote_question == 0)
         {
            fprintf(STDERR,
1227 1228
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
              inname,PNG_ZBUF_SIZE);
1229
            fprintf(STDERR,
1230
              "\n   filtering heuristic (libpng default), compression");
1231
            fprintf(STDERR,
1232
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1233 1234 1235
              ZLIB_VERSION);
            wrote_question=1;
         }
1236 1237
         FCLOSE(fpin);
         FCLOSE(fpout);
1238
         return (0);
G
Guy Schalnat 已提交
1239 1240 1241 1242 1243
      }

      if (!num_in)
         break;

A
Andreas Dilger 已提交
1244
      if (png_memcmp(inbuf, outbuf, num_in))
G
Guy Schalnat 已提交
1245
      {
1246
         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1247 1248 1249
         if(wrote_question == 0)
         {
            fprintf(STDERR,
1250 1251
         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
                 inname,PNG_ZBUF_SIZE);
1252
            fprintf(STDERR,
1253
              "\n   filtering heuristic (libpng default), compression");
1254
            fprintf(STDERR,
1255
              " level (zlib default),\n   and zlib version (%s)?\n\n",
1256 1257 1258
              ZLIB_VERSION);
            wrote_question=1;
         }
1259 1260
         FCLOSE(fpin);
         FCLOSE(fpout);
1261
         return (0);
G
Guy Schalnat 已提交
1262 1263 1264
      }
   }

1265 1266
   FCLOSE(fpin);
   FCLOSE(fpout);
G
Guy Schalnat 已提交
1267

1268
   return (0);
G
Guy Schalnat 已提交
1269
}
G
Guy Schalnat 已提交
1270

1271 1272
/* input and output filenames */
#ifdef RISCOS
1273 1274
static PNG_CONST char *inname = "pngtest/png";
static PNG_CONST char *outname = "pngout/png";
1275
#else
1276 1277
static PNG_CONST char *inname = "pngtest.png";
static PNG_CONST char *outname = "pngout.png";
1278 1279 1280 1281 1282 1283 1284 1285 1286
#endif

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

   fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1287
   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1288
   fprintf(STDERR,"%s",png_get_copyright(NULL));
1289
   /* Show the version of libpng used in building the library */
1290 1291
   fprintf(STDERR," library (%lu):%s", png_access_version_number(),
      png_get_header_version(NULL));
1292
   /* Show the version of libpng used in building the application */
1293
   fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1294
      PNG_HEADER_VERSION_STRING);
1295 1296
   fprintf(STDERR," sizeof(png_struct)=%d, sizeof(png_info)=%d\n",
                    sizeof(png_struct), sizeof(png_info));
1297 1298 1299 1300 1301

   /* 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 */
1302
#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1303
      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1304
#endif
1305
   /* I think the following can happen. */
1306
#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1307
      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1308
#endif
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320

   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)
   {
1321
      if (strcmp(argv[1], "-m") == 0)
1322
      {
1323
         multiple = 1;
1324 1325
         status_dots_requested = 0;
      }
1326 1327 1328 1329 1330
      else if (strcmp(argv[1], "-mv") == 0 ||
               strcmp(argv[1], "-vm") == 0 )
      {
         multiple = 1;
         verbose = 1;
1331
         status_dots_requested = 1;
1332 1333 1334 1335
      }
      else if (strcmp(argv[1], "-v") == 0)
      {
         verbose = 1;
1336
         status_dots_requested = 1;
1337 1338 1339
         inname = argv[2];
      }
      else
1340
      {
1341
         inname = argv[1];
1342 1343
         status_dots_requested = 0;
      }
1344 1345
   }

1346 1347
   if (!multiple && argc == 3+verbose)
     outname = argv[2+verbose];
1348

1349
   if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
1350
   {
1351 1352
     fprintf(STDERR,
       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1353
        argv[0], argv[0]);
1354 1355 1356 1357
     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);
1358 1359 1360 1361 1362 1363
     exit(1);
   }

   if (multiple)
   {
      int i;
1364
#ifdef PNG_USER_MEM_SUPPORTED
1365 1366
      int allocation_now = current_allocation;
#endif
1367
      for (i=2; i<argc; ++i)
1368
      {
1369 1370 1371 1372
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
         int k;
#endif
         int kerror;
1373 1374
         fprintf(STDERR, "Testing %s:",argv[i]);
         kerror = test_one_file(argv[i], outname);
1375
         if (kerror == 0)
1376
         {
1377
#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1378
            fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1379
#else
1380
            fprintf(STDERR, " PASS\n");
1381
#endif
1382 1383 1384 1385 1386 1387
#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
1388 1389 1390 1391 1392 1393 1394 1395
#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
         {
1396 1397
            fprintf(STDERR, " FAIL\n");
            ierror += kerror;
1398 1399
         }
#ifdef PNG_USER_MEM_SUPPORTED
1400 1401 1402
         if (allocation_now != current_allocation)
            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
               current_allocation-allocation_now);
1403 1404
         if (current_allocation != 0)
         {
1405 1406 1407 1408
            memory_infop pinfo = pinformation;

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

1481 1482
             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
                current_allocation);
1483 1484 1485 1486
             while (pinfo != NULL)
             {
                fprintf(STDERR," %d bytes at %x\n",
                   pinfo->size, pinfo->pointer);
1487 1488 1489 1490
                pinfo = pinfo->next;
             }
          }
#endif
1491
       }
1492
#ifdef PNG_USER_MEM_SUPPORTED
1493
       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1494
          current_allocation);
1495
       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1496
          maximum_allocation);
1497 1498 1499 1500
       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
          total_allocation);
       fprintf(STDERR, "     Number of allocations: %10d\n",
            num_allocations);
1501
#endif
1502 1503
   }

1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
#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

1518 1519 1520 1521
   if (ierror == 0)
      fprintf(STDERR, "libpng passes test\n");
   else
      fprintf(STDERR, "libpng FAILS test\n");
1522
   return (int)(ierror != 0);
1523
}
1524

1525
/* Generate a compiler error if there is an old png.h in the search path. */
1526
typedef version_1_0_11beta1 your_png_h_is_not_version_1_0_11beta1;