The BIG graph update
[rrdtool.git] / libraries / libpng-1.2.0 / pngtest.c
1
2 /* pngtest.c - a simple test program to test libpng
3  *
4  * libpng 1.2.0 - September 1, 2001
5  * For conditions of distribution and use, see copyright notice in png.h
6  * Copyright (c) 1998-2001 Glenn Randers-Pehrson
7  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
8  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
9  *
10  * This program reads in a PNG image, writes it out again, and then
11  * compares the two files.  If the files are identical, this shows that
12  * the basic chunk handling, filtering, and (de)compression code is working
13  * properly.  It does not currently test all of the transforms, although
14  * it probably should.
15  *
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  * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
20  *    exist in the input file.
21  * 4) others not listed here...
22  * 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  * If a filename is given on the command-line, then this file is used
26  * for the input, rather than the default "pngtest.png".  This allows
27  * testing a wide variety of files easily.  You can also test a number
28  * of files at once by typing "pngtest -m file1.png file2.png ..."
29  */
30
31 #if defined(_WIN32_WCE)
32 #  if _WIN32_WCE < 211
33      __error__ (f|w)printf functions are not supported on old WindowsCE.;
34 #  endif
35 #  include <windows.h>
36 #  include <stdlib.h>
37 #  define READFILE(file, data, length, check) \
38      if (ReadFile(file, data, length, &check,NULL)) check = 0
39 #  define WRITEFILE(file, data, length, check)) \
40      if (WriteFile(file, data, length, &check, NULL)) check = 0
41 #  define FCLOSE(file) CloseHandle(file)
42 #else
43 #  include <stdio.h>
44 #  include <stdlib.h>
45 #  include <assert.h>
46 #  define READFILE(file, data, length, check) \
47      check=(png_size_t)fread(data,(png_size_t)1,length,file)
48 #  define WRITEFILE(file, data, length, check) \
49      check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
50 #  define FCLOSE(file) fclose(file)
51 #endif
52
53 #if defined(PNG_NO_STDIO)
54 #  if defined(_WIN32_WCE)
55      typedef HANDLE                png_FILE_p;
56 #  else
57      typedef FILE                * png_FILE_p;
58 #  endif
59 #endif
60
61 /* Makes pngtest verbose so we can find problems (needs to be before png.h) */
62 #ifndef PNG_DEBUG
63 #  define PNG_DEBUG 0
64 #endif
65
66 #if !PNG_DEBUG
67 #  define SINGLE_ROWBUF_ALLOC   /* makes buffer overruns easier to nail */
68 #endif
69
70 /* Turn on CPU timing
71 #define PNGTEST_TIMING
72 */
73
74 #ifdef PNG_NO_FLOATING_POINT_SUPPORTED
75 #undef PNGTEST_TIMING
76 #endif
77
78 #ifdef PNGTEST_TIMING
79 static float t_start, t_stop, t_decode, t_encode, t_misc;
80 #include <time.h>
81 #endif
82
83 #include "png.h"
84
85 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
86 #ifndef png_jmpbuf
87 #  define png_jmpbuf(png_ptr) png_ptr->jmpbuf
88 #endif
89
90 #ifdef PNGTEST_TIMING
91 static float t_start, t_stop, t_decode, t_encode, t_misc;
92 #if !defined(PNG_tIME_SUPPORTED)
93 #include <time.h>
94 #endif
95 #endif
96
97 #if defined(PNG_TIME_RFC1123_SUPPORTED)
98 static int tIME_chunk_present=0;
99 static char tIME_string[30] = "no tIME chunk present in file";
100 #endif
101
102 static int verbose = 0;
103
104 int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname));
105
106 #ifdef __TURBOC__
107 #include <mem.h>
108 #endif
109
110 /* defined so I can write to a file on gui/windowing platforms */
111 /*  #define STDERR stderr  */
112 #define STDERR stdout   /* for DOS */
113
114 /* example of using row callbacks to make a simple progress meter */
115 static int status_pass=1;
116 static int status_dots_requested=0;
117 static int status_dots=1;
118
119 void
120 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
121 void
122 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     if(status_pass != pass)
126     {
127        fprintf(stdout,"\n Pass %d: ",pass);
128        status_pass = pass;
129        status_dots = 31;
130     }
131     status_dots--;
132     if(status_dots == 0)
133     {
134        fprintf(stdout, "\n         ");
135        status_dots=30;
136     }
137     fprintf(stdout, "r");
138 }
139
140 void
141 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
142 void
143 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     fprintf(stdout, "w");
147 }
148
149
150 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
151 /* Example of using user transform callback (we don't transform anything,
152    but merely examine the row filters.  We set this to 256 rather than
153    5 in case illegal filter values are present.) */
154 static png_uint_32 filters_used[256];
155 void
156 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
157 void
158 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
159 {
160     if(png_ptr != NULL && row_info != NULL)
161       ++filters_used[*(data-1)];
162 }
163 #endif
164
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 void
172 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    /* contents of row_info:
180     *  png_uint_32 width      width of row
181     *  png_uint_32 rowbytes   number of bytes in row
182     *  png_byte color_type    color type of pixels
183     *  png_byte bit_depth     bit depth of samples
184     *  png_byte channels      number of channels (1-4)
185     *  png_byte pixel_depth   bits per pixel (depth*channels)
186     */
187
188
189     /* counts the number of zero samples (or zero pixels if color_type is 3 */
190
191     if(row_info->color_type == 0 || row_info->color_type == 3)
192     {
193        int pos=0;
194        png_uint_32 n, nstop;
195        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              if(pos == 8)
201              {
202                 pos = 0;
203                 dp++;
204              }
205           }
206           if(row_info->bit_depth == 2)
207           {
208              if(((*dp << (pos+=2)) & 0xc0) == 0) zero_samples++;
209              if(pos == 8)
210              {
211                 pos = 0;
212                 dp++;
213              }
214           }
215           if(row_info->bit_depth == 4)
216           {
217              if(((*dp << (pos+=4)) & 0xf0) == 0) zero_samples++;
218              if(pos == 8)
219              {
220                 pos = 0;
221                 dp++;
222              }
223           }
224           if(row_info->bit_depth == 8)
225              if(*dp++ == 0) zero_samples++;
226           if(row_info->bit_depth == 16)
227           {
228              if((*dp | *(dp+1)) == 0) zero_samples++;
229              dp+=2;
230           }
231        }
232     }
233     else /* other color types */
234     {
235        png_uint_32 n, nstop;
236        int channel;
237        int color_channels = row_info->channels;
238        if(row_info->color_type > 3)color_channels--;
239
240        for (n=0, nstop=row_info->width; n<nstop; n++)
241        {
242           for (channel = 0; channel < color_channels; channel++)
243           {
244              if(row_info->bit_depth == 8)
245                 if(*dp++ == 0) zero_samples++;
246              if(row_info->bit_depth == 16)
247              {
248                 if((*dp | *(dp+1)) == 0) zero_samples++;
249                 dp+=2;
250              }
251           }
252           if(row_info->color_type > 3)
253           {
254              dp++;
255              if(row_info->bit_depth == 16)dp++;
256           }
257        }
258     }
259 }
260 #endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */
261
262 static int wrote_question = 0;
263
264 #if defined(PNG_NO_STDIO)
265 /* START of code to validate stdio-free compilation */
266 /* These copies of the default read/write functions come from pngrio.c and */
267 /* 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    not reading from a standard C stream, you should create a replacement
270    read_data function and use it at run time with png_set_read_fn(), rather
271    than changing the library. */
272
273 #ifndef USE_FAR_KEYWORD
274 static void
275 pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
276 {
277    png_size_t check;
278
279    /* fread() returns 0 on error, so it is OK to store this in a png_size_t
280     * instead of an int, which is what fread() actually returns.
281     */
282    READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check);
283
284    if (check != length)
285    {
286       png_error(png_ptr, "Read Error!");
287    }
288 }
289 #else
290 /* this is the model-independent version. Since the standard I/O library
291    can't handle far buffers in the medium and small models, we have to copy
292    the data.
293 */
294
295 #define NEAR_BUF_SIZE 1024
296 #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    int check;
302    png_byte *n_data;
303    png_FILE_p io_ptr;
304
305    /* Check if data really is near. If so, use usual code. */
306    n_data = (png_byte *)CVT_PTR_NOCHECK(data);
307    io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
308    if ((png_bytep)n_data == data)
309    {
310       READFILE(io_ptr, n_data, length, check);
311    }
312    else
313    {
314       png_byte buf[NEAR_BUF_SIZE];
315       png_size_t read, remaining, err;
316       check = 0;
317       remaining = length;
318       do
319       {
320          read = MIN(NEAR_BUF_SIZE, remaining);
321          READFILE(io_ptr, buf, 1, err);
322          png_memcpy(data, buf, read); /* copy far buffer to near buffer */
323          if(err != read)
324             break;
325          else
326             check += err;
327          data += read;
328          remaining -= read;
329       }
330       while (remaining != 0);
331    }
332    if (check != length)
333    {
334       png_error(png_ptr, "read Error");
335    }
336 }
337 #endif /* USE_FAR_KEYWORD */
338
339 #if defined(PNG_WRITE_FLUSH_SUPPORTED)
340 static void
341 pngtest_flush(png_structp png_ptr)
342 {
343 #if !defined(_WIN32_WCE)
344    png_FILE_p io_ptr;
345    io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
346    if (io_ptr != NULL)
347       fflush(io_ptr);
348 #endif
349 }
350 #endif
351
352 /* This is the function that does the actual writing of data.  If you are
353    not writing to a standard C stream, you should create a replacement
354    write_data function and use it at run time with png_set_write_fn(), rather
355    than changing the library. */
356 #ifndef USE_FAR_KEYWORD
357 static void
358 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
359 {
360    png_uint_32 check;
361
362    WRITEFILE((png_FILE_p)png_ptr->io_ptr,  data, length, check);
363    if (check != length)
364    {
365       png_error(png_ptr, "Write Error");
366    }
367 }
368 #else
369 /* this is the model-independent version. Since the standard I/O library
370    can't handle far buffers in the medium and small models, we have to copy
371    the data.
372 */
373
374 #define NEAR_BUF_SIZE 1024
375 #define MIN(a,b) (a <= b ? a : b)
376
377 static void
378 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
379 {
380    png_uint_32 check;
381    png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
382    png_FILE_p io_ptr;
383
384    /* Check if data really is near. If so, use usual code. */
385    near_data = (png_byte *)CVT_PTR_NOCHECK(data);
386    io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
387    if ((png_bytep)near_data == data)
388    {
389       WRITEFILE(io_ptr, near_data, length, check);
390    }
391    else
392    {
393       png_byte buf[NEAR_BUF_SIZE];
394       png_size_t written, remaining, err;
395       check = 0;
396       remaining = length;
397       do
398       {
399          written = MIN(NEAR_BUF_SIZE, remaining);
400          png_memcpy(buf, data, written); /* copy far buffer to near buffer */
401          WRITEFILE(io_ptr, buf, written, err);
402          if (err != written)
403             break;
404          else
405             check += err;
406          data += written;
407          remaining -= written;
408       }
409       while (remaining != 0);
410    }
411    if (check != length)
412    {
413       png_error(png_ptr, "Write Error");
414    }
415 }
416
417 #endif /* USE_FAR_KEYWORD */
418
419 /* This function is called when there is a warning, but the library thinks
420  * it can continue anyway.  Replacement functions don't have to do anything
421  * here if you don't want to.  In the default configuration, png_ptr is
422  * not used, but it is passed in case it may be useful.
423  */
424 static void
425 pngtest_warning(png_structp png_ptr, png_const_charp message)
426 {
427    PNG_CONST char *name = "UNKNOWN (ERROR!)";
428    if (png_ptr != NULL && png_ptr->error_ptr != NULL)
429       name = png_ptr->error_ptr;
430    fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
431 }
432
433 /* This is the default error handling function.  Note that replacements for
434  * this function MUST NOT RETURN, or the program will likely crash.  This
435  * function is used by default, or if the program supplies NULL for the
436  * error function pointer in png_set_error_fn().
437  */
438 static void
439 pngtest_error(png_structp png_ptr, png_const_charp message)
440 {
441    pngtest_warning(png_ptr, message);
442    /* We can return because png_error calls the default handler, which is
443     * actually OK in this case. */
444 }
445 #endif /* PNG_NO_STDIO */
446 /* END of code to validate stdio-free compilation */
447
448 /* START of code to validate memory allocation and deallocation */
449 #ifdef PNG_USER_MEM_SUPPORTED
450
451 /* Allocate memory.  For reasonable files, size should never exceed
452    64K.  However, zlib may allocate more then 64K if you don't tell
453    it not to.  See zconf.h and png.h for more information.  zlib does
454    need to allocate exactly 64K, so whatever you call here must
455    have the ability to do that.
456
457    This piece of code can be compiled to validate max 64K allocations
458    by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. */
459 typedef struct memory_information
460 {
461    png_uint_32               size;
462    png_voidp                 pointer;
463    struct memory_information FAR *next;
464 } memory_information;
465 typedef memory_information FAR *memory_infop;
466
467 static memory_infop pinformation = NULL;
468 static int current_allocation = 0;
469 static int maximum_allocation = 0;
470 static int total_allocation = 0;
471 static int num_allocations = 0;
472
473 png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
474 void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
475
476 png_voidp
477 png_debug_malloc(png_structp png_ptr, png_uint_32 size)
478 {
479
480    /* png_malloc has already tested for NULL; png_create_struct calls
481       png_debug_malloc directly, with png_ptr == NULL which is OK */
482
483    if (size == 0)
484       return (png_voidp)(NULL);
485
486    /* This calls the library allocator twice, once to get the requested
487       buffer and once to get a new free list entry. */
488    {
489       memory_infop pinfo = (memory_infop)png_malloc_default(png_ptr,
490          (png_uint_32)sizeof *pinfo);
491       pinfo->size = size;
492       current_allocation += size;
493       total_allocation += size;
494       num_allocations ++;
495       if (current_allocation > maximum_allocation)
496          maximum_allocation = current_allocation;
497       pinfo->pointer = (png_voidp)png_malloc_default(png_ptr, size);
498       pinfo->next = pinformation;
499       pinformation = pinfo;
500       /* Make sure the caller isn't assuming zeroed memory. */
501       png_memset(pinfo->pointer, 0xdd, pinfo->size);
502 #if PNG_DEBUG
503       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 /* Free a pointer.  It is removed from the list at the same time. */
512 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    if (ptr == 0)
518    {
519 #if 0 /* This happens all the time. */
520       fprintf(STDERR, "WARNING: freeing NULL pointer\n");
521 #endif
522       return;
523    }
524
525    /* Unlink the element from the list. */
526    {
527       memory_infop FAR *ppinfo = &pinformation;
528       for (;;)
529       {
530          memory_infop pinfo = *ppinfo;
531          if (pinfo->pointer == ptr)
532          {
533             *ppinfo = pinfo->next;
534             current_allocation -= pinfo->size;
535             if (current_allocation < 0)
536                fprintf(STDERR, "Duplicate free of memory\n");
537             /* 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             break;
543          }
544          if (pinfo->next == NULL)
545          {
546             fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
547             break;
548          }
549          ppinfo = &pinfo->next;
550       }
551    }
552
553    /* Finally free the data. */
554 #if PNG_DEBUG
555    if(verbose)
556       printf("Freeing %x\n",ptr);
557 #endif
558    png_free_default(png_ptr, ptr);
559    ptr=NULL;
560 }
561 #endif /* PNG_USER_MEM_SUPPORTED */
562 /* END of code to test memory allocation/deallocation */
563
564 /* Test one file */
565 int
566 test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
567 {
568    static png_FILE_p fpin;
569    static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
570    png_structp read_ptr;
571    png_infop read_info_ptr, end_info_ptr;
572 #ifdef PNG_WRITE_SUPPORTED
573    png_structp write_ptr;
574    png_infop write_info_ptr;
575    png_infop write_end_info_ptr;
576 #else
577    png_structp write_ptr = NULL;
578    png_infop write_info_ptr = NULL;
579    png_infop write_end_info_ptr = NULL;
580 #endif
581    png_bytep row_buf;
582    png_uint_32 y;
583    png_uint_32 width, height;
584    int num_pass, pass;
585    int bit_depth, color_type;
586 #ifdef PNG_SETJMP_SUPPORTED
587 #ifdef USE_FAR_KEYWORD
588    jmp_buf jmpbuf;
589 #endif
590 #endif
591
592 #if defined(_WIN32_WCE)
593    TCHAR path[MAX_PATH];
594 #endif
595    char inbuf[256], outbuf[256];
596
597    row_buf = (png_bytep)NULL;
598
599 #if defined(_WIN32_WCE)
600    MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
601    if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
602 #else
603    if ((fpin = fopen(inname, "rb")) == NULL)
604 #endif
605    {
606       fprintf(STDERR, "Could not find input file %s\n", inname);
607       return (1);
608    }
609
610 #if defined(_WIN32_WCE)
611    MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
612    if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
613 #else
614    if ((fpout = fopen(outname, "wb")) == NULL)
615 #endif
616    {
617       fprintf(STDERR, "Could not open output file %s\n", outname);
618       FCLOSE(fpin);
619       return (1);
620    }
621
622    png_debug(0, "Allocating read and write structures\n");
623 #ifdef PNG_USER_MEM_SUPPORTED
624    read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
625       (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
626       (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
627 #else
628    read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
629       (png_error_ptr)NULL, (png_error_ptr)NULL);
630 #endif
631 #if defined(PNG_NO_STDIO)
632    png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
633        pngtest_warning);
634 #endif
635 #ifdef PNG_WRITE_SUPPORTED
636 #ifdef PNG_USER_MEM_SUPPORTED
637    write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
638       (png_error_ptr)NULL, (png_error_ptr)NULL, (png_voidp)NULL,
639       (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
640 #else
641    write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL,
642       (png_error_ptr)NULL, (png_error_ptr)NULL);
643 #endif
644 #if defined(PNG_NO_STDIO)
645    png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
646        pngtest_warning);
647 #endif
648 #endif
649    png_debug(0, "Allocating read_info, write_info and end_info structures\n");
650    read_info_ptr = png_create_info_struct(read_ptr);
651    end_info_ptr = png_create_info_struct(read_ptr);
652 #ifdef PNG_WRITE_SUPPORTED
653    write_info_ptr = png_create_info_struct(write_ptr);
654    write_end_info_ptr = png_create_info_struct(write_ptr);
655 #endif
656
657 #ifdef PNG_SETJMP_SUPPORTED
658    png_debug(0, "Setting jmpbuf for read struct\n");
659 #ifdef USE_FAR_KEYWORD
660    if (setjmp(jmpbuf))
661 #else
662    if (setjmp(png_jmpbuf(read_ptr)))
663 #endif
664    {
665       fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
666       png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
667 #ifdef PNG_WRITE_SUPPORTED
668       png_destroy_info_struct(write_ptr, &write_end_info_ptr);
669       png_destroy_write_struct(&write_ptr, &write_info_ptr);
670 #endif
671       FCLOSE(fpin);
672       FCLOSE(fpout);
673       return (1);
674    }
675 #ifdef USE_FAR_KEYWORD
676    png_memcpy(png_jmpbuf(read_ptr),jmpbuf,sizeof(jmp_buf));
677 #endif
678
679 #ifdef PNG_WRITE_SUPPORTED
680    png_debug(0, "Setting jmpbuf for write struct\n");
681 #ifdef USE_FAR_KEYWORD
682    if (setjmp(jmpbuf))
683 #else
684    if (setjmp(png_jmpbuf(write_ptr)))
685 #endif
686    {
687       fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
688       png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
689       png_destroy_info_struct(write_ptr, &write_end_info_ptr);
690 #ifdef PNG_WRITE_SUPPORTED
691       png_destroy_write_struct(&write_ptr, &write_info_ptr);
692 #endif
693       FCLOSE(fpin);
694       FCLOSE(fpout);
695       return (1);
696    }
697 #ifdef USE_FAR_KEYWORD
698    png_memcpy(png_jmpbuf(write_ptr),jmpbuf,sizeof(jmp_buf));
699 #endif
700 #endif
701 #endif
702
703    png_debug(0, "Initializing input and output streams\n");
704 #if !defined(PNG_NO_STDIO)
705    png_init_io(read_ptr, fpin);
706 #  ifdef PNG_WRITE_SUPPORTED
707    png_init_io(write_ptr, fpout);
708 #  endif
709 #else
710    png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
711 #  ifdef PNG_WRITE_SUPPORTED
712    png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
713 #    if defined(PNG_WRITE_FLUSH_SUPPORTED)
714       pngtest_flush);
715 #    else
716       NULL);
717 #    endif
718 #  endif
719 #endif
720    if(status_dots_requested == 1)
721    {
722 #ifdef PNG_WRITE_SUPPORTED
723       png_set_write_status_fn(write_ptr, write_row_callback);
724 #endif
725       png_set_read_status_fn(read_ptr, read_row_callback);
726    }
727    else
728    {
729 #ifdef PNG_WRITE_SUPPORTED
730       png_set_write_status_fn(write_ptr, NULL);
731 #endif
732       png_set_read_status_fn(read_ptr, NULL);
733    }
734
735 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
736    {
737      int i;
738      for(i=0; i<256; i++)
739         filters_used[i]=0;
740      png_set_read_user_transform_fn(read_ptr, count_filters);
741    }
742 #endif
743 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
744    zero_samples=0;
745    png_set_write_user_transform_fn(write_ptr, count_zero_samples);
746 #endif
747
748 #define HANDLE_CHUNK_IF_SAFE      2
749 #define HANDLE_CHUNK_ALWAYS       3
750 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
751    png_set_keep_unknown_chunks(read_ptr, HANDLE_CHUNK_ALWAYS, NULL, 0);
752 #endif
753 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
754    png_set_keep_unknown_chunks(write_ptr, HANDLE_CHUNK_IF_SAFE, NULL, 0);
755 #endif
756
757    png_debug(0, "Reading info struct\n");
758    png_read_info(read_ptr, read_info_ptr);
759
760    png_debug(0, "Transferring info struct\n");
761    {
762       int interlace_type, compression_type, filter_type;
763
764       if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
765           &color_type, &interlace_type, &compression_type, &filter_type))
766       {
767          png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
768 #if defined(PNG_WRITE_INTERLACING_SUPPORTED)
769             color_type, interlace_type, compression_type, filter_type);
770 #else
771             color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
772 #endif
773       }
774    }
775 #if defined(PNG_FIXED_POINT_SUPPORTED)
776 #if defined(PNG_cHRM_SUPPORTED)
777    {
778       png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
779          blue_y;
780       if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
781          &red_y, &green_x, &green_y, &blue_x, &blue_y))
782       {
783          png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
784             red_y, green_x, green_y, blue_x, blue_y);
785       }
786    }
787 #endif
788 #if defined(PNG_gAMA_SUPPORTED)
789    {
790       png_fixed_point gamma;
791
792       if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
793       {
794          png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
795       }
796    }
797 #endif
798 #else /* Use floating point versions */
799 #if defined(PNG_FLOATING_POINT_SUPPORTED)
800 #if defined(PNG_cHRM_SUPPORTED)
801    {
802       double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
803          blue_y;
804       if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
805          &red_y, &green_x, &green_y, &blue_x, &blue_y))
806       {
807          png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
808             red_y, green_x, green_y, blue_x, blue_y);
809       }
810    }
811 #endif
812 #if defined(PNG_gAMA_SUPPORTED)
813    {
814       double gamma;
815
816       if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
817       {
818          png_set_gAMA(write_ptr, write_info_ptr, gamma);
819       }
820    }
821 #endif
822 #endif /* floating point */
823 #endif /* fixed point */
824 #if defined(PNG_iCCP_SUPPORTED)
825    {
826       png_charp name;
827       png_charp profile;
828       png_uint_32 proflen;
829       int compression_type;
830
831       if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
832                       &profile, &proflen))
833       {
834          png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
835                       profile, proflen);
836       }
837    }
838 #endif
839 #if defined(PNG_sRGB_SUPPORTED)
840    {
841       int intent;
842
843       if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
844       {
845          png_set_sRGB(write_ptr, write_info_ptr, intent);
846       }
847    }
848 #endif
849    {
850       png_colorp palette;
851       int num_palette;
852
853       if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
854       {
855          png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
856       }
857    }
858 #if defined(PNG_bKGD_SUPPORTED)
859    {
860       png_color_16p background;
861
862       if (png_get_bKGD(read_ptr, read_info_ptr, &background))
863       {
864          png_set_bKGD(write_ptr, write_info_ptr, background);
865       }
866    }
867 #endif
868 #if defined(PNG_hIST_SUPPORTED)
869    {
870       png_uint_16p hist;
871
872       if (png_get_hIST(read_ptr, read_info_ptr, &hist))
873       {
874          png_set_hIST(write_ptr, write_info_ptr, hist);
875       }
876    }
877 #endif
878 #if defined(PNG_oFFs_SUPPORTED)
879    {
880       png_int_32 offset_x, offset_y;
881       int unit_type;
882
883       if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
884       {
885          png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
886       }
887    }
888 #endif
889 #if defined(PNG_pCAL_SUPPORTED)
890    {
891       png_charp purpose, units;
892       png_charpp params;
893       png_int_32 X0, X1;
894       int type, nparams;
895
896       if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
897          &nparams, &units, &params))
898       {
899          png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
900             nparams, units, params);
901       }
902    }
903 #endif
904 #if defined(PNG_pHYs_SUPPORTED)
905    {
906       png_uint_32 res_x, res_y;
907       int unit_type;
908
909       if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
910       {
911          png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
912       }
913    }
914 #endif
915 #if defined(PNG_sBIT_SUPPORTED)
916    {
917       png_color_8p sig_bit;
918
919       if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
920       {
921          png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
922       }
923    }
924 #endif
925 #if defined(PNG_sCAL_SUPPORTED)
926 #ifdef PNG_FLOATING_POINT_SUPPORTED
927    {
928       int unit;
929       double scal_width, scal_height;
930
931       if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
932          &scal_height))
933       {
934          png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
935       }
936    }
937 #else
938 #ifdef PNG_FIXED_POINT_SUPPORTED
939    {
940       int unit;
941       png_charp scal_width, scal_height;
942
943       if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
944           &scal_height))
945       {
946          png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
947       }
948    }
949 #endif
950 #endif
951 #endif
952 #if defined(PNG_TEXT_SUPPORTED)
953    {
954       png_textp text_ptr;
955       int num_text;
956
957       if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
958       {
959          png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
960          png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
961       }
962    }
963 #endif
964 #if defined(PNG_tIME_SUPPORTED)
965    {
966       png_timep mod_time;
967
968       if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
969       {
970          png_set_tIME(write_ptr, write_info_ptr, mod_time);
971 #if defined(PNG_TIME_RFC1123_SUPPORTED)
972          /* we have to use png_strcpy instead of "=" because the string
973             pointed to by png_convert_to_rfc1123() gets free'ed before
974             we use it */
975          png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
976          tIME_chunk_present++;
977 #endif /* PNG_TIME_RFC1123_SUPPORTED */
978       }
979    }
980 #endif
981 #if defined(PNG_tRNS_SUPPORTED)
982    {
983       png_bytep trans;
984       int num_trans;
985       png_color_16p trans_values;
986
987       if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
988          &trans_values))
989       {
990          png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
991             trans_values);
992       }
993    }
994 #endif
995 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
996    {
997       png_unknown_chunkp unknowns;
998       int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
999          &unknowns);
1000       if (num_unknowns)
1001       {
1002          png_size_t i;
1003          png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1004            num_unknowns);
1005          /* copy the locations from the read_info_ptr.  The automatically
1006             generated locations in write_info_ptr are wrong because we
1007             haven't written anything yet */
1008          for (i = 0; i < (png_size_t)num_unknowns; i++)
1009            png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1010              unknowns[i].location);
1011       }
1012    }
1013 #endif
1014
1015 #ifdef PNG_WRITE_SUPPORTED
1016    png_debug(0, "\nWriting info struct\n");
1017
1018 /* If we wanted, we could write info in two steps:
1019    png_write_info_before_PLTE(write_ptr, write_info_ptr);
1020  */
1021    png_write_info(write_ptr, write_info_ptr);
1022 #endif
1023
1024 #ifdef SINGLE_ROWBUF_ALLOC
1025    png_debug(0, "\nAllocating row buffer...");
1026    row_buf = (png_bytep)png_malloc(read_ptr,
1027       png_get_rowbytes(read_ptr, read_info_ptr));
1028    png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
1029 #endif /* SINGLE_ROWBUF_ALLOC */
1030    png_debug(0, "Writing row data\n");
1031
1032 #if defined(PNG_READ_INTERLACING_SUPPORTED) || \
1033   defined(PNG_WRITE_INTERLACING_SUPPORTED)
1034    num_pass = png_set_interlace_handling(read_ptr);
1035 #  ifdef PNG_WRITE_SUPPORTED
1036    png_set_interlace_handling(write_ptr);
1037 #  endif
1038 #else
1039    num_pass=1;
1040 #endif
1041
1042 #ifdef PNGTEST_TIMING
1043    t_stop = (float)clock();
1044    t_misc += (t_stop - t_start);
1045    t_start = t_stop;
1046 #endif
1047    for (pass = 0; pass < num_pass; pass++)
1048    {
1049       png_debug1(0, "Writing row data for pass %d\n",pass);
1050       for (y = 0; y < height; y++)
1051       {
1052 #ifndef SINGLE_ROWBUF_ALLOC
1053          png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y);
1054          row_buf = (png_bytep)png_malloc(read_ptr,
1055             png_get_rowbytes(read_ptr, read_info_ptr));
1056          png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
1057             png_get_rowbytes(read_ptr, read_info_ptr));
1058 #endif /* !SINGLE_ROWBUF_ALLOC */
1059          png_read_rows(read_ptr, (png_bytepp)&row_buf, (png_bytepp)NULL, 1);
1060
1061 #ifdef PNG_WRITE_SUPPORTED
1062 #ifdef PNGTEST_TIMING
1063          t_stop = (float)clock();
1064          t_decode += (t_stop - t_start);
1065          t_start = t_stop;
1066 #endif
1067          png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1068 #ifdef PNGTEST_TIMING
1069          t_stop = (float)clock();
1070          t_encode += (t_stop - t_start);
1071          t_start = t_stop;
1072 #endif
1073 #endif /* PNG_WRITE_SUPPORTED */
1074
1075 #ifndef SINGLE_ROWBUF_ALLOC
1076          png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y);
1077          png_free(read_ptr, row_buf);
1078 #endif /* !SINGLE_ROWBUF_ALLOC */
1079       }
1080    }
1081
1082 #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1083    png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1084 #endif
1085 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1086    png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1087 #endif
1088
1089    png_debug(0, "Reading and writing end_info data\n");
1090
1091    png_read_end(read_ptr, end_info_ptr);
1092 #if defined(PNG_TEXT_SUPPORTED)
1093    {
1094       png_textp text_ptr;
1095       int num_text;
1096
1097       if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
1098       {
1099          png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1100          png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
1101       }
1102    }
1103 #endif
1104 #if defined(PNG_tIME_SUPPORTED)
1105    {
1106       png_timep mod_time;
1107
1108       if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
1109       {
1110          png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1111 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1112          /* we have to use png_strcpy instead of "=" because the string
1113             pointed to by png_convert_to_rfc1123() gets free'ed before
1114             we use it */
1115          png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
1116          tIME_chunk_present++;
1117 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1118       }
1119    }
1120 #endif
1121 #if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1122    {
1123       png_unknown_chunkp unknowns;
1124       int num_unknowns;
1125       num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
1126          &unknowns);
1127       if (num_unknowns)
1128       {
1129          png_size_t i;
1130          png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1131            num_unknowns);
1132          /* copy the locations from the read_info_ptr.  The automatically
1133             generated locations in write_end_info_ptr are wrong because we
1134             haven't written the end_info yet */
1135          for (i = 0; i < (png_size_t)num_unknowns; i++)
1136            png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1137              unknowns[i].location);
1138       }
1139    }
1140 #endif
1141 #ifdef PNG_WRITE_SUPPORTED
1142    png_write_end(write_ptr, write_end_info_ptr);
1143 #endif
1144
1145 #ifdef PNG_EASY_ACCESS_SUPPORTED
1146    if(verbose)
1147    {
1148       png_uint_32 iwidth, iheight;
1149       iwidth = png_get_image_width(write_ptr, write_info_ptr);
1150       iheight = png_get_image_height(write_ptr, write_info_ptr);
1151       fprintf(STDERR, "Image width = %lu, height = %lu\n",
1152          iwidth, iheight);
1153    }
1154 #endif
1155
1156    png_debug(0, "Destroying data structs\n");
1157 #ifdef SINGLE_ROWBUF_ALLOC
1158    png_debug(1, "destroying row_buf for read_ptr\n");
1159    png_free(read_ptr, row_buf);
1160    row_buf=NULL;
1161 #endif /* SINGLE_ROWBUF_ALLOC */
1162    png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
1163    png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1164 #ifdef PNG_WRITE_SUPPORTED
1165    png_debug(1, "destroying write_end_info_ptr\n");
1166    png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1167    png_debug(1, "destroying write_ptr, write_info_ptr\n");
1168    png_destroy_write_struct(&write_ptr, &write_info_ptr);
1169 #endif
1170    png_debug(0, "Destruction complete.\n");
1171
1172    FCLOSE(fpin);
1173    FCLOSE(fpout);
1174
1175    png_debug(0, "Opening files for comparison\n");
1176 #if defined(_WIN32_WCE)
1177    MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
1178    if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1179 #else
1180    if ((fpin = fopen(inname, "rb")) == NULL)
1181 #endif
1182    {
1183       fprintf(STDERR, "Could not find file %s\n", inname);
1184       return (1);
1185    }
1186
1187 #if defined(_WIN32_WCE)
1188    MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
1189    if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1190 #else
1191    if ((fpout = fopen(outname, "rb")) == NULL)
1192 #endif
1193    {
1194       fprintf(STDERR, "Could not find file %s\n", outname);
1195       FCLOSE(fpin);
1196       return (1);
1197    }
1198
1199    for(;;)
1200    {
1201       png_size_t num_in, num_out;
1202
1203       READFILE(fpin, inbuf, 1, num_in);
1204       READFILE(fpout, outbuf, 1, num_out);
1205
1206       if (num_in != num_out)
1207       {
1208          fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1209                  inname, outname);
1210          if(wrote_question == 0)
1211          {
1212             fprintf(STDERR,
1213          "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1214               inname,PNG_ZBUF_SIZE);
1215             fprintf(STDERR,
1216               "\n   filtering heuristic (libpng default), compression");
1217             fprintf(STDERR,
1218               " level (zlib default),\n   and zlib version (%s)?\n\n",
1219               ZLIB_VERSION);
1220             wrote_question=1;
1221          }
1222          FCLOSE(fpin);
1223          FCLOSE(fpout);
1224          return (0);
1225       }
1226
1227       if (!num_in)
1228          break;
1229
1230       if (png_memcmp(inbuf, outbuf, num_in))
1231       {
1232          fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1233          if(wrote_question == 0)
1234          {
1235             fprintf(STDERR,
1236          "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1237                  inname,PNG_ZBUF_SIZE);
1238             fprintf(STDERR,
1239               "\n   filtering heuristic (libpng default), compression");
1240             fprintf(STDERR,
1241               " level (zlib default),\n   and zlib version (%s)?\n\n",
1242               ZLIB_VERSION);
1243             wrote_question=1;
1244          }
1245          FCLOSE(fpin);
1246          FCLOSE(fpout);
1247          return (0);
1248       }
1249    }
1250
1251    FCLOSE(fpin);
1252    FCLOSE(fpout);
1253
1254    return (0);
1255 }
1256
1257 /* input and output filenames */
1258 #ifdef RISCOS
1259 static PNG_CONST char *inname = "pngtest/png";
1260 static PNG_CONST char *outname = "pngout/png";
1261 #else
1262 static PNG_CONST char *inname = "pngtest.png";
1263 static PNG_CONST char *outname = "pngout.png";
1264 #endif
1265
1266 int
1267 main(int argc, char *argv[])
1268 {
1269    int multiple = 0;
1270    int ierror = 0;
1271
1272    fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1273    fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1274    fprintf(STDERR,"%s",png_get_copyright(NULL));
1275    /* Show the version of libpng used in building the library */
1276    fprintf(STDERR," library (%lu):%s", png_access_version_number(),
1277       png_get_header_version(NULL));
1278    /* Show the version of libpng used in building the application */
1279    fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1280       PNG_HEADER_VERSION_STRING);
1281    fprintf(STDERR," sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n",
1282                     (long)sizeof(png_struct), (long)sizeof(png_info));
1283
1284    /* Do some consistency checking on the memory allocation settings, I'm
1285       not sure this matters, but it is nice to know, the first of these
1286       tests should be impossible because of the way the macros are set
1287       in pngconf.h */
1288 #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1289       fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1290 #endif
1291    /* I think the following can happen. */
1292 #if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1293       fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1294 #endif
1295
1296    if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
1297    {
1298       fprintf(STDERR,
1299          "Warning: versions are different between png.h and png.c\n");
1300       fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
1301       fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
1302       ++ierror;
1303    }
1304
1305    if (argc > 1)
1306    {
1307       if (strcmp(argv[1], "-m") == 0)
1308       {
1309          multiple = 1;
1310          status_dots_requested = 0;
1311       }
1312       else if (strcmp(argv[1], "-mv") == 0 ||
1313                strcmp(argv[1], "-vm") == 0 )
1314       {
1315          multiple = 1;
1316          verbose = 1;
1317          status_dots_requested = 1;
1318       }
1319       else if (strcmp(argv[1], "-v") == 0)
1320       {
1321          verbose = 1;
1322          status_dots_requested = 1;
1323          inname = argv[2];
1324       }
1325       else
1326       {
1327          inname = argv[1];
1328          status_dots_requested = 0;
1329       }
1330    }
1331
1332    if (!multiple && argc == 3+verbose)
1333      outname = argv[2+verbose];
1334
1335    if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
1336    {
1337      fprintf(STDERR,
1338        "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1339         argv[0], argv[0]);
1340      fprintf(STDERR,
1341        "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
1342      fprintf(STDERR,
1343        "  with -m %s is used as a temporary file\n", outname);
1344      exit(1);
1345    }
1346
1347    if (multiple)
1348    {
1349       int i;
1350 #ifdef PNG_USER_MEM_SUPPORTED
1351       int allocation_now = current_allocation;
1352 #endif
1353       for (i=2; i<argc; ++i)
1354       {
1355 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1356          int k;
1357 #endif
1358          int kerror;
1359          fprintf(STDERR, "Testing %s:",argv[i]);
1360          kerror = test_one_file(argv[i], outname);
1361          if (kerror == 0)
1362          {
1363 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1364             fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1365 #else
1366             fprintf(STDERR, " PASS\n");
1367 #endif
1368 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1369             for (k=0; k<256; k++)
1370                if(filters_used[k])
1371                   fprintf(STDERR, " Filter %d was used %lu times\n",
1372                      k,filters_used[k]);
1373 #endif
1374 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1375          if(tIME_chunk_present != 0)
1376             fprintf(STDERR, " tIME = %s\n",tIME_string);
1377          tIME_chunk_present = 0;
1378 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1379          }
1380          else
1381          {
1382             fprintf(STDERR, " FAIL\n");
1383             ierror += kerror;
1384          }
1385 #ifdef PNG_USER_MEM_SUPPORTED
1386          if (allocation_now != current_allocation)
1387             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1388                current_allocation-allocation_now);
1389          if (current_allocation != 0)
1390          {
1391             memory_infop pinfo = pinformation;
1392
1393             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1394                current_allocation);
1395             while (pinfo != NULL)
1396             {
1397                fprintf(STDERR, " %lu bytes at %x\n", pinfo->size, 
1398                  (unsigned int) pinfo->pointer);
1399                pinfo = pinfo->next;
1400             }
1401          }
1402 #endif
1403       }
1404 #ifdef PNG_USER_MEM_SUPPORTED
1405          fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1406             current_allocation);
1407          fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1408             maximum_allocation);
1409          fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1410             total_allocation);
1411          fprintf(STDERR, "     Number of allocations: %10d\n",
1412             num_allocations);
1413 #endif
1414    }
1415    else
1416    {
1417       int i;
1418       for (i=0; i<3; ++i)
1419       {
1420          int kerror;
1421 #ifdef PNG_USER_MEM_SUPPORTED
1422          int allocation_now = current_allocation;
1423 #endif
1424          if (i == 1) status_dots_requested = 1;
1425          else if(verbose == 0)status_dots_requested = 0;
1426          if (i == 0 || verbose == 1 || ierror != 0)
1427             fprintf(STDERR, "Testing %s:",inname);
1428          kerror = test_one_file(inname, outname);
1429          if(kerror == 0)
1430          {
1431             if(verbose == 1 || i == 2)
1432             {
1433 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1434                 int k;
1435 #endif
1436 #if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1437                 fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1438 #else
1439                 fprintf(STDERR, " PASS\n");
1440 #endif
1441 #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1442                 for (k=0; k<256; k++)
1443                    if(filters_used[k])
1444                       fprintf(STDERR, " Filter %d was used %lu times\n",
1445                          k,filters_used[k]);
1446 #endif
1447 #if defined(PNG_TIME_RFC1123_SUPPORTED)
1448              if(tIME_chunk_present != 0)
1449                 fprintf(STDERR, " tIME = %s\n",tIME_string);
1450 #endif /* PNG_TIME_RFC1123_SUPPORTED */
1451             }
1452          }
1453          else
1454          {
1455             if(verbose == 0 && i != 2)
1456                fprintf(STDERR, "Testing %s:",inname);
1457             fprintf(STDERR, " FAIL\n");
1458             ierror += kerror;
1459          }
1460 #ifdef PNG_USER_MEM_SUPPORTED
1461          if (allocation_now != current_allocation)
1462              fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1463                current_allocation-allocation_now);
1464          if (current_allocation != 0)
1465          {
1466              memory_infop pinfo = pinformation;
1467
1468              fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1469                 current_allocation);
1470              while (pinfo != NULL)
1471              {
1472                 fprintf(STDERR," %lu bytes at %x\n",
1473                    pinfo->size, (unsigned int)pinfo->pointer);
1474                 pinfo = pinfo->next;
1475              }
1476           }
1477 #endif
1478        }
1479 #ifdef PNG_USER_MEM_SUPPORTED
1480        fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1481           current_allocation);
1482        fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1483           maximum_allocation);
1484        fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1485           total_allocation);
1486        fprintf(STDERR, "     Number of allocations: %10d\n",
1487             num_allocations);
1488 #endif
1489    }
1490
1491 #ifdef PNGTEST_TIMING
1492    t_stop = (float)clock();
1493    t_misc += (t_stop - t_start);
1494    t_start = t_stop;
1495    fprintf(STDERR," CPU time used = %.3f seconds",
1496       (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1497    fprintf(STDERR," (decoding %.3f,\n",
1498       t_decode/(float)CLOCKS_PER_SEC);
1499    fprintf(STDERR,"        encoding %.3f ,",
1500       t_encode/(float)CLOCKS_PER_SEC);
1501    fprintf(STDERR," other %.3f seconds)\n\n",
1502       t_misc/(float)CLOCKS_PER_SEC);
1503 #endif
1504
1505    if (ierror == 0)
1506       fprintf(STDERR, "libpng passes test\n");
1507    else
1508       fprintf(STDERR, "libpng FAILS test\n");
1509    return (int)(ierror != 0);
1510 }
1511
1512 /* Generate a compiler error if there is an old png.h in the search path. */
1513 typedef version_1_2_0 your_png_h_is_not_version_1_2_0;