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