1
2/* pngtest.c - a simple test program to test libpng
3 *
4 * libpng 1.2.7 - September 12, 2004
5 * For conditions of distribution and use, see copyright notice in png.h
6 * Copyright (c) 1998-2004 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#include "png.h"
32
33#if defined(_WIN32_WCE)
34#  if _WIN32_WCE < 211
35     __error__ (f|w)printf functions are not supported on old WindowsCE.;
36#  endif
37#  include <windows.h>
38#  include <stdlib.h>
39#  define READFILE(file, data, length, check) \
40     if (ReadFile(file, data, length, &check,NULL)) check = 0
41#  define WRITEFILE(file, data, length, check)) \
42     if (WriteFile(file, data, length, &check, NULL)) check = 0
43#  define FCLOSE(file) CloseHandle(file)
44#else
45#  include <stdio.h>
46#  include <stdlib.h>
47#  include <assert.h>
48#  define READFILE(file, data, length, check) \
49     check=(png_size_t)fread(data,(png_size_t)1,length,file)
50#  define WRITEFILE(file, data, length, check) \
51     check=(png_size_t)fwrite(data,(png_size_t)1, length, file)
52#  define FCLOSE(file) fclose(file)
53#endif
54
55#if defined(PNG_NO_STDIO)
56#  if defined(_WIN32_WCE)
57     typedef HANDLE                png_FILE_p;
58#  else
59     typedef FILE                * png_FILE_p;
60#  endif
61#endif
62
63/* Makes pngtest verbose so we can find problems (needs to be before png.h) */
64#ifndef PNG_DEBUG
65#  define PNG_DEBUG 0
66#endif
67
68#if !PNG_DEBUG
69#  define SINGLE_ROWBUF_ALLOC  /* makes buffer overruns easier to nail */
70#endif
71
72/* Turn on CPU timing
73#define PNGTEST_TIMING
74*/
75
76#ifdef PNG_NO_FLOATING_POINT_SUPPORTED
77#undef PNGTEST_TIMING
78#endif
79
80#ifdef PNGTEST_TIMING
81static float t_start, t_stop, t_decode, t_encode, t_misc;
82#include <time.h>
83#endif
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
91static 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)
98static int tIME_chunk_present=0;
99static char tIME_string[30] = "no tIME chunk present in file";
100#endif
101
102static int verbose = 0;
103
104int 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 */
115static int status_pass=1;
116static int status_dots_requested=0;
117static int status_dots=1;
118
119void
120#ifdef PNG_1_0_X
121PNGAPI
122#endif
123read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
124void
125#ifdef PNG_1_0_X
126PNGAPI
127#endif
128read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
129{
130    if(png_ptr == NULL || row_number > PNG_UINT_31_MAX) 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
146void
147#ifdef PNG_1_0_X
148PNGAPI
149#endif
150write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass);
151void
152#ifdef PNG_1_0_X
153PNGAPI
154#endif
155write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
156{
157    if(png_ptr == NULL || row_number > PNG_UINT_31_MAX || 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.) */
166static png_uint_32 filters_used[256];
167void
168#ifdef PNG_1_0_X
169PNGAPI
170#endif
171count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data);
172void
173#ifdef PNG_1_0_X
174PNGAPI
175#endif
176count_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
187static png_uint_32 zero_samples;
188
189void
190#ifdef PNG_1_0_X
191PNGAPI
192#endif
193count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data);
194void
195#ifdef PNG_1_0_X
196PNGAPI
197#endif
198count_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
286static 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
298static void
299pngtest_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
322static void
323pngtest_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)
364static void
365pngtest_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
381static void
382pngtest_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
401static void
402pngtest_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 */
448static void
449pngtest_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 */
462static void
463pngtest_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#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
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. */
483typedef struct memory_information
484{
485   png_uint_32               size;
486   png_voidp                 pointer;
487   struct memory_information FAR *next;
488} memory_information;
489typedef memory_information FAR *memory_infop;
490
491static memory_infop pinformation = NULL;
492static int current_allocation = 0;
493static int maximum_allocation = 0;
494static int total_allocation = 0;
495static int num_allocations = 0;
496
497png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size));
498void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
499
500png_voidp
501png_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      /* Disable malloc_fn and free_fn */
514      memory_infop pinfo;
515      png_set_mem_fn(png_ptr, NULL, NULL, NULL);
516      pinfo = (memory_infop)png_malloc(png_ptr,
517         (png_uint_32)png_sizeof (*pinfo));
518      pinfo->size = size;
519      current_allocation += size;
520      total_allocation += size;
521      num_allocations ++;
522      if (current_allocation > maximum_allocation)
523         maximum_allocation = current_allocation;
524      pinfo->pointer = (png_voidp)png_malloc(png_ptr, size);
525      /* Restore malloc_fn and free_fn */
526      png_set_mem_fn(png_ptr, png_voidp_NULL, (png_malloc_ptr)png_debug_malloc,
527         (png_free_ptr)png_debug_free);
528      if (size != 0 && pinfo->pointer == NULL)
529      {
530         current_allocation -= size;
531         total_allocation -= size;
532         png_error(png_ptr,
533           "out of memory in pngtest->png_debug_malloc.");
534      }
535      pinfo->next = pinformation;
536      pinformation = pinfo;
537      /* Make sure the caller isn't assuming zeroed memory. */
538      png_memset(pinfo->pointer, 0xdd, pinfo->size);
539      if(verbose)
540         printf("png_malloc %lu bytes at %x\n",size,pinfo->pointer);
541      assert(pinfo->size != 12345678);
542      return (png_voidp)(pinfo->pointer);
543   }
544}
545
546/* Free a pointer.  It is removed from the list at the same time. */
547void
548png_debug_free(png_structp png_ptr, png_voidp ptr)
549{
550   if (png_ptr == NULL)
551      fprintf(STDERR, "NULL pointer to png_debug_free.\n");
552   if (ptr == 0)
553   {
554#if 0 /* This happens all the time. */
555      fprintf(STDERR, "WARNING: freeing NULL pointer\n");
556#endif
557      return;
558   }
559
560   /* Unlink the element from the list. */
561   {
562      memory_infop FAR *ppinfo = &pinformation;
563      for (;;)
564      {
565         memory_infop pinfo = *ppinfo;
566         if (pinfo->pointer == ptr)
567         {
568            *ppinfo = pinfo->next;
569            current_allocation -= pinfo->size;
570            if (current_allocation < 0)
571               fprintf(STDERR, "Duplicate free of memory\n");
572            /* We must free the list element too, but first kill
573               the memory that is to be freed. */
574            png_memset(ptr, 0x55, pinfo->size);
575            png_free_default(png_ptr, pinfo);
576            pinfo=NULL;
577            break;
578         }
579         if (pinfo->next == NULL)
580         {
581            fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr);
582            break;
583         }
584         ppinfo = &pinfo->next;
585      }
586   }
587
588   /* Finally free the data. */
589   if(verbose)
590      printf("Freeing %x\n",ptr);
591   png_free_default(png_ptr, ptr);
592   ptr=NULL;
593}
594#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */
595/* END of code to test memory allocation/deallocation */
596
597/* Test one file */
598int
599test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
600{
601   static png_FILE_p fpin;
602   static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
603   png_structp read_ptr;
604   png_infop read_info_ptr, end_info_ptr;
605#ifdef PNG_WRITE_SUPPORTED
606   png_structp write_ptr;
607   png_infop write_info_ptr;
608   png_infop write_end_info_ptr;
609#else
610   png_structp write_ptr = NULL;
611   png_infop write_info_ptr = NULL;
612   png_infop write_end_info_ptr = NULL;
613#endif
614   png_bytep row_buf;
615   png_uint_32 y;
616   png_uint_32 width, height;
617   int num_pass, pass;
618   int bit_depth, color_type;
619#ifdef PNG_SETJMP_SUPPORTED
620#ifdef USE_FAR_KEYWORD
621   jmp_buf jmpbuf;
622#endif
623#endif
624
625#if defined(_WIN32_WCE)
626   TCHAR path[MAX_PATH];
627#endif
628   char inbuf[256], outbuf[256];
629
630   row_buf = NULL;
631
632#if defined(_WIN32_WCE)
633   MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
634   if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
635#else
636   if ((fpin = fopen(inname, "rb")) == NULL)
637#endif
638   {
639      fprintf(STDERR, "Could not find input file %s\n", inname);
640      return (1);
641   }
642
643#if defined(_WIN32_WCE)
644   MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
645   if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE)
646#else
647   if ((fpout = fopen(outname, "wb")) == NULL)
648#endif
649   {
650      fprintf(STDERR, "Could not open output file %s\n", outname);
651      FCLOSE(fpin);
652      return (1);
653   }
654
655   png_debug(0, "Allocating read and write structures\n");
656#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
657   read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
658      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
659      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
660#else
661   read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
662      png_error_ptr_NULL, png_error_ptr_NULL);
663#endif
664#if defined(PNG_NO_STDIO)
665   png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
666       pngtest_warning);
667#endif
668#ifdef PNG_WRITE_SUPPORTED
669#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
670   write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
671      png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL,
672      (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free);
673#else
674   write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL,
675      png_error_ptr_NULL, png_error_ptr_NULL);
676#endif
677#if defined(PNG_NO_STDIO)
678   png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
679       pngtest_warning);
680#endif
681#endif
682   png_debug(0, "Allocating read_info, write_info and end_info structures\n");
683   read_info_ptr = png_create_info_struct(read_ptr);
684   end_info_ptr = png_create_info_struct(read_ptr);
685#ifdef PNG_WRITE_SUPPORTED
686   write_info_ptr = png_create_info_struct(write_ptr);
687   write_end_info_ptr = png_create_info_struct(write_ptr);
688#endif
689
690#ifdef PNG_SETJMP_SUPPORTED
691   png_debug(0, "Setting jmpbuf for read struct\n");
692#ifdef USE_FAR_KEYWORD
693   if (setjmp(jmpbuf))
694#else
695   if (setjmp(png_jmpbuf(read_ptr)))
696#endif
697   {
698      fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
699      if (row_buf)
700         png_free(read_ptr, row_buf);
701      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
702#ifdef PNG_WRITE_SUPPORTED
703      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
704      png_destroy_write_struct(&write_ptr, &write_info_ptr);
705#endif
706      FCLOSE(fpin);
707      FCLOSE(fpout);
708      return (1);
709   }
710#ifdef USE_FAR_KEYWORD
711   png_memcpy(png_jmpbuf(read_ptr),jmpbuf,png_sizeof(jmp_buf));
712#endif
713
714#ifdef PNG_WRITE_SUPPORTED
715   png_debug(0, "Setting jmpbuf for write struct\n");
716#ifdef USE_FAR_KEYWORD
717   if (setjmp(jmpbuf))
718#else
719   if (setjmp(png_jmpbuf(write_ptr)))
720#endif
721   {
722      fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
723      png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
724      png_destroy_info_struct(write_ptr, &write_end_info_ptr);
725#ifdef PNG_WRITE_SUPPORTED
726      png_destroy_write_struct(&write_ptr, &write_info_ptr);
727#endif
728      FCLOSE(fpin);
729      FCLOSE(fpout);
730      return (1);
731   }
732#ifdef USE_FAR_KEYWORD
733   png_memcpy(png_jmpbuf(write_ptr),jmpbuf,png_sizeof(jmp_buf));
734#endif
735#endif
736#endif
737
738   png_debug(0, "Initializing input and output streams\n");
739#if !defined(PNG_NO_STDIO)
740   png_init_io(read_ptr, fpin);
741#  ifdef PNG_WRITE_SUPPORTED
742   png_init_io(write_ptr, fpout);
743#  endif
744#else
745   png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
746#  ifdef PNG_WRITE_SUPPORTED
747   png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
748#    if defined(PNG_WRITE_FLUSH_SUPPORTED)
749      pngtest_flush);
750#    else
751      NULL);
752#    endif
753#  endif
754#endif
755   if(status_dots_requested == 1)
756   {
757#ifdef PNG_WRITE_SUPPORTED
758      png_set_write_status_fn(write_ptr, write_row_callback);
759#endif
760      png_set_read_status_fn(read_ptr, read_row_callback);
761   }
762   else
763   {
764#ifdef PNG_WRITE_SUPPORTED
765      png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL);
766#endif
767      png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL);
768   }
769
770#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
771   {
772     int i;
773     for(i=0; i<256; i++)
774        filters_used[i]=0;
775     png_set_read_user_transform_fn(read_ptr, count_filters);
776   }
777#endif
778#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
779   zero_samples=0;
780   png_set_write_user_transform_fn(write_ptr, count_zero_samples);
781#endif
782
783#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
784#  ifndef PNG_HANDLE_CHUNK_ALWAYS
785#    define PNG_HANDLE_CHUNK_ALWAYS       3
786#  endif
787   png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
788      png_bytep_NULL, 0);
789#endif
790#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
791#  ifndef PNG_HANDLE_CHUNK_IF_SAFE
792#    define PNG_HANDLE_CHUNK_IF_SAFE      2
793#  endif
794   png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE,
795      png_bytep_NULL, 0);
796#endif
797
798   png_debug(0, "Reading info struct\n");
799   png_read_info(read_ptr, read_info_ptr);
800
801   png_debug(0, "Transferring info struct\n");
802   {
803      int interlace_type, compression_type, filter_type;
804
805      if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
806          &color_type, &interlace_type, &compression_type, &filter_type))
807      {
808         png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
809#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
810            color_type, interlace_type, compression_type, filter_type);
811#else
812            color_type, PNG_INTERLACE_NONE, compression_type, filter_type);
813#endif
814      }
815   }
816#if defined(PNG_FIXED_POINT_SUPPORTED)
817#if defined(PNG_cHRM_SUPPORTED)
818   {
819      png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
820         blue_y;
821      if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
822         &red_y, &green_x, &green_y, &blue_x, &blue_y))
823      {
824         png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
825            red_y, green_x, green_y, blue_x, blue_y);
826      }
827   }
828#endif
829#if defined(PNG_gAMA_SUPPORTED)
830   {
831      png_fixed_point gamma;
832
833      if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma))
834      {
835         png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
836      }
837   }
838#endif
839#else /* Use floating point versions */
840#if defined(PNG_FLOATING_POINT_SUPPORTED)
841#if defined(PNG_cHRM_SUPPORTED)
842   {
843      double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
844         blue_y;
845      if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
846         &red_y, &green_x, &green_y, &blue_x, &blue_y))
847      {
848         png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
849            red_y, green_x, green_y, blue_x, blue_y);
850      }
851   }
852#endif
853#if defined(PNG_gAMA_SUPPORTED)
854   {
855      double gamma;
856
857      if (png_get_gAMA(read_ptr, read_info_ptr, &gamma))
858      {
859         png_set_gAMA(write_ptr, write_info_ptr, gamma);
860      }
861   }
862#endif
863#endif /* floating point */
864#endif /* fixed point */
865#if defined(PNG_iCCP_SUPPORTED)
866   {
867      png_charp name;
868      png_charp profile;
869      png_uint_32 proflen;
870      int compression_type;
871
872      if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
873                      &profile, &proflen))
874      {
875         png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
876                      profile, proflen);
877      }
878   }
879#endif
880#if defined(PNG_sRGB_SUPPORTED)
881   {
882      int intent;
883
884      if (png_get_sRGB(read_ptr, read_info_ptr, &intent))
885      {
886         png_set_sRGB(write_ptr, write_info_ptr, intent);
887      }
888   }
889#endif
890   {
891      png_colorp palette;
892      int num_palette;
893
894      if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette))
895      {
896         png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
897      }
898   }
899#if defined(PNG_bKGD_SUPPORTED)
900   {
901      png_color_16p background;
902
903      if (png_get_bKGD(read_ptr, read_info_ptr, &background))
904      {
905         png_set_bKGD(write_ptr, write_info_ptr, background);
906      }
907   }
908#endif
909#if defined(PNG_hIST_SUPPORTED)
910   {
911      png_uint_16p hist;
912
913      if (png_get_hIST(read_ptr, read_info_ptr, &hist))
914      {
915         png_set_hIST(write_ptr, write_info_ptr, hist);
916      }
917   }
918#endif
919#if defined(PNG_oFFs_SUPPORTED)
920   {
921      png_int_32 offset_x, offset_y;
922      int unit_type;
923
924      if (png_get_oFFs(read_ptr, read_info_ptr,&offset_x,&offset_y,&unit_type))
925      {
926         png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
927      }
928   }
929#endif
930#if defined(PNG_pCAL_SUPPORTED)
931   {
932      png_charp purpose, units;
933      png_charpp params;
934      png_int_32 X0, X1;
935      int type, nparams;
936
937      if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
938         &nparams, &units, &params))
939      {
940         png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
941            nparams, units, params);
942      }
943   }
944#endif
945#if defined(PNG_pHYs_SUPPORTED)
946   {
947      png_uint_32 res_x, res_y;
948      int unit_type;
949
950      if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type))
951      {
952         png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
953      }
954   }
955#endif
956#if defined(PNG_sBIT_SUPPORTED)
957   {
958      png_color_8p sig_bit;
959
960      if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit))
961      {
962         png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
963      }
964   }
965#endif
966#if defined(PNG_sCAL_SUPPORTED)
967#ifdef PNG_FLOATING_POINT_SUPPORTED
968   {
969      int unit;
970      double scal_width, scal_height;
971
972      if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
973         &scal_height))
974      {
975         png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
976      }
977   }
978#else
979#ifdef PNG_FIXED_POINT_SUPPORTED
980   {
981      int unit;
982      png_charp scal_width, scal_height;
983
984      if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
985          &scal_height))
986      {
987         png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height);
988      }
989   }
990#endif
991#endif
992#endif
993#if defined(PNG_TEXT_SUPPORTED)
994   {
995      png_textp text_ptr;
996      int num_text;
997
998      if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
999      {
1000         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1001         png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
1002      }
1003   }
1004#endif
1005#if defined(PNG_tIME_SUPPORTED)
1006   {
1007      png_timep mod_time;
1008
1009      if (png_get_tIME(read_ptr, read_info_ptr, &mod_time))
1010      {
1011         png_set_tIME(write_ptr, write_info_ptr, mod_time);
1012#if defined(PNG_TIME_RFC1123_SUPPORTED)
1013         /* we have to use png_strcpy instead of "=" because the string
1014            pointed to by png_convert_to_rfc1123() gets free'ed before
1015            we use it */
1016         png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
1017         tIME_chunk_present++;
1018#endif /* PNG_TIME_RFC1123_SUPPORTED */
1019      }
1020   }
1021#endif
1022#if defined(PNG_tRNS_SUPPORTED)
1023   {
1024      png_bytep trans;
1025      int num_trans;
1026      png_color_16p trans_values;
1027
1028      if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans,
1029         &trans_values))
1030      {
1031         png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans,
1032            trans_values);
1033      }
1034   }
1035#endif
1036#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1037   {
1038      png_unknown_chunkp unknowns;
1039      int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr,
1040         &unknowns);
1041      if (num_unknowns)
1042      {
1043         png_size_t i;
1044         png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1045           num_unknowns);
1046         /* copy the locations from the read_info_ptr.  The automatically
1047            generated locations in write_info_ptr are wrong because we
1048            haven't written anything yet */
1049         for (i = 0; i < (png_size_t)num_unknowns; i++)
1050           png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1051             unknowns[i].location);
1052      }
1053   }
1054#endif
1055
1056#ifdef PNG_WRITE_SUPPORTED
1057   png_debug(0, "\nWriting info struct\n");
1058
1059/* If we wanted, we could write info in two steps:
1060   png_write_info_before_PLTE(write_ptr, write_info_ptr);
1061 */
1062   png_write_info(write_ptr, write_info_ptr);
1063#endif
1064
1065#ifdef SINGLE_ROWBUF_ALLOC
1066   png_debug(0, "\nAllocating row buffer...");
1067   row_buf = (png_bytep)png_malloc(read_ptr,
1068      png_get_rowbytes(read_ptr, read_info_ptr));
1069   png_debug1(0, "0x%08lx\n\n", (unsigned long)row_buf);
1070#endif /* SINGLE_ROWBUF_ALLOC */
1071   png_debug(0, "Writing row data\n");
1072
1073#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
1074  defined(PNG_WRITE_INTERLACING_SUPPORTED)
1075   num_pass = png_set_interlace_handling(read_ptr);
1076#  ifdef PNG_WRITE_SUPPORTED
1077   png_set_interlace_handling(write_ptr);
1078#  endif
1079#else
1080   num_pass=1;
1081#endif
1082
1083#ifdef PNGTEST_TIMING
1084   t_stop = (float)clock();
1085   t_misc += (t_stop - t_start);
1086   t_start = t_stop;
1087#endif
1088   for (pass = 0; pass < num_pass; pass++)
1089   {
1090      png_debug1(0, "Writing row data for pass %d\n",pass);
1091      for (y = 0; y < height; y++)
1092      {
1093#ifndef SINGLE_ROWBUF_ALLOC
1094         png_debug2(0, "\nAllocating row buffer (pass %d, y = %ld)...", pass,y);
1095         row_buf = (png_bytep)png_malloc(read_ptr,
1096            png_get_rowbytes(read_ptr, read_info_ptr));
1097         png_debug2(0, "0x%08lx (%ld bytes)\n", (unsigned long)row_buf,
1098            png_get_rowbytes(read_ptr, read_info_ptr));
1099#endif /* !SINGLE_ROWBUF_ALLOC */
1100         png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1);
1101
1102#ifdef PNG_WRITE_SUPPORTED
1103#ifdef PNGTEST_TIMING
1104         t_stop = (float)clock();
1105         t_decode += (t_stop - t_start);
1106         t_start = t_stop;
1107#endif
1108         png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1109#ifdef PNGTEST_TIMING
1110         t_stop = (float)clock();
1111         t_encode += (t_stop - t_start);
1112         t_start = t_stop;
1113#endif
1114#endif /* PNG_WRITE_SUPPORTED */
1115
1116#ifndef SINGLE_ROWBUF_ALLOC
1117         png_debug2(0, "Freeing row buffer (pass %d, y = %ld)\n\n", pass, y);
1118         png_free(read_ptr, row_buf);
1119#endif /* !SINGLE_ROWBUF_ALLOC */
1120      }
1121   }
1122
1123#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
1124   png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1125#endif
1126#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1127   png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1128#endif
1129
1130   png_debug(0, "Reading and writing end_info data\n");
1131
1132   png_read_end(read_ptr, end_info_ptr);
1133#if defined(PNG_TEXT_SUPPORTED)
1134   {
1135      png_textp text_ptr;
1136      int num_text;
1137
1138      if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
1139      {
1140         png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks\n", num_text);
1141         png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
1142      }
1143   }
1144#endif
1145#if defined(PNG_tIME_SUPPORTED)
1146   {
1147      png_timep mod_time;
1148
1149      if (png_get_tIME(read_ptr, end_info_ptr, &mod_time))
1150      {
1151         png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1152#if defined(PNG_TIME_RFC1123_SUPPORTED)
1153         /* we have to use png_strcpy instead of "=" because the string
1154            pointed to by png_convert_to_rfc1123() gets free'ed before
1155            we use it */
1156         png_strcpy(tIME_string,png_convert_to_rfc1123(read_ptr, mod_time));
1157         tIME_chunk_present++;
1158#endif /* PNG_TIME_RFC1123_SUPPORTED */
1159      }
1160   }
1161#endif
1162#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
1163   {
1164      png_unknown_chunkp unknowns;
1165      int num_unknowns;
1166      num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr,
1167         &unknowns);
1168      if (num_unknowns)
1169      {
1170         png_size_t i;
1171         png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1172           num_unknowns);
1173         /* copy the locations from the read_info_ptr.  The automatically
1174            generated locations in write_end_info_ptr are wrong because we
1175            haven't written the end_info yet */
1176         for (i = 0; i < (png_size_t)num_unknowns; i++)
1177           png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1178             unknowns[i].location);
1179      }
1180   }
1181#endif
1182#ifdef PNG_WRITE_SUPPORTED
1183   png_write_end(write_ptr, write_end_info_ptr);
1184#endif
1185
1186#ifdef PNG_EASY_ACCESS_SUPPORTED
1187   if(verbose)
1188   {
1189      png_uint_32 iwidth, iheight;
1190      iwidth = png_get_image_width(write_ptr, write_info_ptr);
1191      iheight = png_get_image_height(write_ptr, write_info_ptr);
1192      fprintf(STDERR, "Image width = %lu, height = %lu\n",
1193         iwidth, iheight);
1194   }
1195#endif
1196
1197   png_debug(0, "Destroying data structs\n");
1198#ifdef SINGLE_ROWBUF_ALLOC
1199   png_debug(1, "destroying row_buf for read_ptr\n");
1200   png_free(read_ptr, row_buf);
1201   row_buf=NULL;
1202#endif /* SINGLE_ROWBUF_ALLOC */
1203   png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr\n");
1204   png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1205#ifdef PNG_WRITE_SUPPORTED
1206   png_debug(1, "destroying write_end_info_ptr\n");
1207   png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1208   png_debug(1, "destroying write_ptr, write_info_ptr\n");
1209   png_destroy_write_struct(&write_ptr, &write_info_ptr);
1210#endif
1211   png_debug(0, "Destruction complete.\n");
1212
1213   FCLOSE(fpin);
1214   FCLOSE(fpout);
1215
1216   png_debug(0, "Opening files for comparison\n");
1217#if defined(_WIN32_WCE)
1218   MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH);
1219   if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1220#else
1221   if ((fpin = fopen(inname, "rb")) == NULL)
1222#endif
1223   {
1224      fprintf(STDERR, "Could not find file %s\n", inname);
1225      return (1);
1226   }
1227
1228#if defined(_WIN32_WCE)
1229   MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH);
1230   if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
1231#else
1232   if ((fpout = fopen(outname, "rb")) == NULL)
1233#endif
1234   {
1235      fprintf(STDERR, "Could not find file %s\n", outname);
1236      FCLOSE(fpin);
1237      return (1);
1238   }
1239
1240   for(;;)
1241   {
1242      png_size_t num_in, num_out;
1243
1244      READFILE(fpin, inbuf, 1, num_in);
1245      READFILE(fpout, outbuf, 1, num_out);
1246
1247      if (num_in != num_out)
1248      {
1249         fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1250                 inname, outname);
1251         if(wrote_question == 0)
1252         {
1253            fprintf(STDERR,
1254         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1255              inname,PNG_ZBUF_SIZE);
1256            fprintf(STDERR,
1257              "\n   filtering heuristic (libpng default), compression");
1258            fprintf(STDERR,
1259              " level (zlib default),\n   and zlib version (%s)?\n\n",
1260              ZLIB_VERSION);
1261            wrote_question=1;
1262         }
1263         FCLOSE(fpin);
1264         FCLOSE(fpout);
1265         return (0);
1266      }
1267
1268      if (!num_in)
1269         break;
1270
1271      if (png_memcmp(inbuf, outbuf, num_in))
1272      {
1273         fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname);
1274         if(wrote_question == 0)
1275         {
1276            fprintf(STDERR,
1277         "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1278                 inname,PNG_ZBUF_SIZE);
1279            fprintf(STDERR,
1280              "\n   filtering heuristic (libpng default), compression");
1281            fprintf(STDERR,
1282              " level (zlib default),\n   and zlib version (%s)?\n\n",
1283              ZLIB_VERSION);
1284            wrote_question=1;
1285         }
1286         FCLOSE(fpin);
1287         FCLOSE(fpout);
1288         return (0);
1289      }
1290   }
1291
1292   FCLOSE(fpin);
1293   FCLOSE(fpout);
1294
1295   return (0);
1296}
1297
1298/* input and output filenames */
1299#ifdef RISCOS
1300static PNG_CONST char *inname = "pngtest/png";
1301static PNG_CONST char *outname = "pngout/png";
1302#else
1303static PNG_CONST char *inname = "pngtest.png";
1304static PNG_CONST char *outname = "pngout.png";
1305#endif
1306
1307int
1308main(int argc, char *argv[])
1309{
1310   int multiple = 0;
1311   int ierror = 0;
1312
1313   fprintf(STDERR, "Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1314   fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1315   fprintf(STDERR,"%s",png_get_copyright(NULL));
1316   /* Show the version of libpng used in building the library */
1317   fprintf(STDERR," library (%lu):%s", png_access_version_number(),
1318      png_get_header_version(NULL));
1319   /* Show the version of libpng used in building the application */
1320   fprintf(STDERR," pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1321      PNG_HEADER_VERSION_STRING);
1322   fprintf(STDERR," png_sizeof(png_struct)=%ld, png_sizeof(png_info)=%ld\n",
1323                    (long)png_sizeof(png_struct), (long)png_sizeof(png_info));
1324
1325   /* Do some consistency checking on the memory allocation settings, I'm
1326      not sure this matters, but it is nice to know, the first of these
1327      tests should be impossible because of the way the macros are set
1328      in pngconf.h */
1329#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1330      fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1331#endif
1332   /* I think the following can happen. */
1333#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1334      fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1335#endif
1336
1337   if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
1338   {
1339      fprintf(STDERR,
1340         "Warning: versions are different between png.h and png.c\n");
1341      fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
1342      fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
1343      ++ierror;
1344   }
1345
1346   if (argc > 1)
1347   {
1348      if (strcmp(argv[1], "-m") == 0)
1349      {
1350         multiple = 1;
1351         status_dots_requested = 0;
1352      }
1353      else if (strcmp(argv[1], "-mv") == 0 ||
1354               strcmp(argv[1], "-vm") == 0 )
1355      {
1356         multiple = 1;
1357         verbose = 1;
1358         status_dots_requested = 1;
1359      }
1360      else if (strcmp(argv[1], "-v") == 0)
1361      {
1362         verbose = 1;
1363         status_dots_requested = 1;
1364         inname = argv[2];
1365      }
1366      else
1367      {
1368         inname = argv[1];
1369         status_dots_requested = 0;
1370      }
1371   }
1372
1373   if (!multiple && argc == 3+verbose)
1374     outname = argv[2+verbose];
1375
1376   if ((!multiple && argc > 3+verbose) || (multiple && argc < 2))
1377   {
1378     fprintf(STDERR,
1379       "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1380        argv[0], argv[0]);
1381     fprintf(STDERR,
1382       "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
1383     fprintf(STDERR,
1384       "  with -m %s is used as a temporary file\n", outname);
1385     exit(1);
1386   }
1387
1388   if (multiple)
1389   {
1390      int i;
1391#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1392      int allocation_now = current_allocation;
1393#endif
1394      for (i=2; i<argc; ++i)
1395      {
1396#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1397         int k;
1398#endif
1399         int kerror;
1400         fprintf(STDERR, "Testing %s:",argv[i]);
1401         kerror = test_one_file(argv[i], outname);
1402         if (kerror == 0)
1403         {
1404#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1405            fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1406#else
1407            fprintf(STDERR, " PASS\n");
1408#endif
1409#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1410            for (k=0; k<256; k++)
1411               if(filters_used[k])
1412                  fprintf(STDERR, " Filter %d was used %lu times\n",
1413                     k,filters_used[k]);
1414#endif
1415#if defined(PNG_TIME_RFC1123_SUPPORTED)
1416         if(tIME_chunk_present != 0)
1417            fprintf(STDERR, " tIME = %s\n",tIME_string);
1418         tIME_chunk_present = 0;
1419#endif /* PNG_TIME_RFC1123_SUPPORTED */
1420         }
1421         else
1422         {
1423            fprintf(STDERR, " FAIL\n");
1424            ierror += kerror;
1425         }
1426#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1427         if (allocation_now != current_allocation)
1428            fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1429               current_allocation-allocation_now);
1430         if (current_allocation != 0)
1431         {
1432            memory_infop pinfo = pinformation;
1433
1434            fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1435               current_allocation);
1436            while (pinfo != NULL)
1437            {
1438               fprintf(STDERR, " %lu bytes at %x\n", pinfo->size,
1439                 (unsigned int) pinfo->pointer);
1440               pinfo = pinfo->next;
1441            }
1442         }
1443#endif
1444      }
1445#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1446         fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1447            current_allocation);
1448         fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1449            maximum_allocation);
1450         fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1451            total_allocation);
1452         fprintf(STDERR, "     Number of allocations: %10d\n",
1453            num_allocations);
1454#endif
1455   }
1456   else
1457   {
1458      int i;
1459      for (i=0; i<3; ++i)
1460      {
1461         int kerror;
1462#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1463         int allocation_now = current_allocation;
1464#endif
1465         if (i == 1) status_dots_requested = 1;
1466         else if(verbose == 0)status_dots_requested = 0;
1467         if (i == 0 || verbose == 1 || ierror != 0)
1468            fprintf(STDERR, "Testing %s:",inname);
1469         kerror = test_one_file(inname, outname);
1470         if(kerror == 0)
1471         {
1472            if(verbose == 1 || i == 2)
1473            {
1474#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1475                int k;
1476#endif
1477#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1478                fprintf(STDERR, "\n PASS (%lu zero samples)\n",zero_samples);
1479#else
1480                fprintf(STDERR, " PASS\n");
1481#endif
1482#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
1483                for (k=0; k<256; k++)
1484                   if(filters_used[k])
1485                      fprintf(STDERR, " Filter %d was used %lu times\n",
1486                         k,filters_used[k]);
1487#endif
1488#if defined(PNG_TIME_RFC1123_SUPPORTED)
1489             if(tIME_chunk_present != 0)
1490                fprintf(STDERR, " tIME = %s\n",tIME_string);
1491#endif /* PNG_TIME_RFC1123_SUPPORTED */
1492            }
1493         }
1494         else
1495         {
1496            if(verbose == 0 && i != 2)
1497               fprintf(STDERR, "Testing %s:",inname);
1498            fprintf(STDERR, " FAIL\n");
1499            ierror += kerror;
1500         }
1501#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1502         if (allocation_now != current_allocation)
1503             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1504               current_allocation-allocation_now);
1505         if (current_allocation != 0)
1506         {
1507             memory_infop pinfo = pinformation;
1508
1509             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1510                current_allocation);
1511             while (pinfo != NULL)
1512             {
1513                fprintf(STDERR," %lu bytes at %x\n",
1514                   pinfo->size, (unsigned int)pinfo->pointer);
1515                pinfo = pinfo->next;
1516             }
1517          }
1518#endif
1519       }
1520#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1521       fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1522          current_allocation);
1523       fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1524          maximum_allocation);
1525       fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1526          total_allocation);
1527       fprintf(STDERR, "     Number of allocations: %10d\n",
1528            num_allocations);
1529#endif
1530   }
1531
1532#ifdef PNGTEST_TIMING
1533   t_stop = (float)clock();
1534   t_misc += (t_stop - t_start);
1535   t_start = t_stop;
1536   fprintf(STDERR," CPU time used = %.3f seconds",
1537      (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1538   fprintf(STDERR," (decoding %.3f,\n",
1539      t_decode/(float)CLOCKS_PER_SEC);
1540   fprintf(STDERR,"        encoding %.3f ,",
1541      t_encode/(float)CLOCKS_PER_SEC);
1542   fprintf(STDERR," other %.3f seconds)\n\n",
1543      t_misc/(float)CLOCKS_PER_SEC);
1544#endif
1545
1546   if (ierror == 0)
1547      fprintf(STDERR, "libpng passes test\n");
1548   else
1549      fprintf(STDERR, "libpng FAILS test\n");
1550   return (int)(ierror != 0);
1551}
1552
1553/* Generate a compiler error if there is an old png.h in the search path. */
1554typedef version_1_2_7 your_png_h_is_not_version_1_2_7;
1555