1 
2 /* pngtest.c - a simple test program to test libpng
3  *
4  * Last changed in libpng 1.6.18 [July 23, 2015]
5  * Copyright (c) 1998-2015 Glenn Randers-Pehrson
6  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8  *
9  * This code is released under the libpng license.
10  * For conditions of distribution and use, see the disclaimer
11  * and license in png.h
12  *
13  * This program reads in a PNG image, writes it out again, and then
14  * compares the two files.  If the files are identical, this shows that
15  * the basic chunk handling, filtering, and (de)compression code is working
16  * properly.  It does not currently test all of the transforms, although
17  * it probably should.
18  *
19  * The program will report "FAIL" in certain legitimate cases:
20  * 1) when the compression level or filter selection method is changed.
21  * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192.
22  * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks
23  *    exist in the input file.
24  * 4) others not listed here...
25  * In these cases, it is best to check with another tool such as "pngcheck"
26  * to see what the differences between the two files are.
27  *
28  * If a filename is given on the command-line, then this file is used
29  * for the input, rather than the default "pngtest.png".  This allows
30  * testing a wide variety of files easily.  You can also test a number
31  * of files at once by typing "pngtest -m file1.png file2.png ..."
32  */
33 
34 #define _POSIX_SOURCE 1
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 
40 /* Defined so I can write to a file on gui/windowing platforms */
41 /*  #define STDERR stderr  */
42 #define STDERR stdout   /* For DOS */
43 
44 #include "png.h"
45 
46 /* Known chunks that exist in pngtest.png must be supported or pngtest will fail
47  * simply as a result of re-ordering them.  This may be fixed in 1.7
48  *
49  * pngtest allocates a single row buffer for each row and overwrites it,
50  * therefore if the write side doesn't support the writing of interlaced images
51  * nothing can be done for an interlaced image (and the code below will fail
52  * horribly trying to write extra data after writing garbage).
53  */
54 #if defined PNG_READ_SUPPORTED && /* else nothing can be done */\
55    defined PNG_READ_bKGD_SUPPORTED &&\
56    defined PNG_READ_cHRM_SUPPORTED &&\
57    defined PNG_READ_gAMA_SUPPORTED &&\
58    defined PNG_READ_oFFs_SUPPORTED &&\
59    defined PNG_READ_pCAL_SUPPORTED &&\
60    defined PNG_READ_pHYs_SUPPORTED &&\
61    defined PNG_READ_sBIT_SUPPORTED &&\
62    defined PNG_READ_sCAL_SUPPORTED &&\
63    defined PNG_READ_sRGB_SUPPORTED &&\
64    defined PNG_READ_tEXt_SUPPORTED &&\
65    defined PNG_READ_tIME_SUPPORTED &&\
66    defined PNG_READ_zTXt_SUPPORTED &&\
67    defined PNG_WRITE_INTERLACING_SUPPORTED
68 
69 #ifdef PNG_ZLIB_HEADER
70 #  include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */
71 #else
72 #  include "zlib.h"
73 #endif
74 
75 /* Copied from pngpriv.h but only used in error messages below. */
76 #ifndef PNG_ZBUF_SIZE
77 #  define PNG_ZBUF_SIZE 8192
78 #endif
79 #define FCLOSE(file) fclose(file)
80 
81 #ifndef PNG_STDIO_SUPPORTED
82 typedef FILE                * png_FILE_p;
83 #endif
84 
85 /* Makes pngtest verbose so we can find problems. */
86 #ifndef PNG_DEBUG
87 #  define PNG_DEBUG 0
88 #endif
89 
90 #if PNG_DEBUG > 1
91 #  define pngtest_debug(m)        ((void)fprintf(stderr, m "\n"))
92 #  define pngtest_debug1(m,p1)    ((void)fprintf(stderr, m "\n", p1))
93 #  define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2))
94 #else
95 #  define pngtest_debug(m)        ((void)0)
96 #  define pngtest_debug1(m,p1)    ((void)0)
97 #  define pngtest_debug2(m,p1,p2) ((void)0)
98 #endif
99 
100 #if !PNG_DEBUG
101 #  define SINGLE_ROWBUF_ALLOC  /* Makes buffer overruns easier to nail */
102 #endif
103 
104 /* Turn on CPU timing
105 #define PNGTEST_TIMING
106 */
107 
108 #ifndef PNG_FLOATING_POINT_SUPPORTED
109 #undef PNGTEST_TIMING
110 #endif
111 
112 #ifdef PNGTEST_TIMING
113 static float t_start, t_stop, t_decode, t_encode, t_misc;
114 #include <time.h>
115 #endif
116 
117 #ifdef PNG_TIME_RFC1123_SUPPORTED
118 #define PNG_tIME_STRING_LENGTH 29
119 static int tIME_chunk_present = 0;
120 static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
121 #endif
122 
123 static int verbose = 0;
124 static int strict = 0;
125 static int relaxed = 0;
126 static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
127 static int error_count = 0; /* count calls to png_error */
128 static int warning_count = 0; /* count calls to png_warning */
129 
130 /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
131 #ifndef png_jmpbuf
132 #  define png_jmpbuf(png_ptr) png_ptr->jmpbuf
133 #endif
134 
135 /* Defines for unknown chunk handling if required. */
136 #ifndef PNG_HANDLE_CHUNK_ALWAYS
137 #  define PNG_HANDLE_CHUNK_ALWAYS       3
138 #endif
139 #ifndef PNG_HANDLE_CHUNK_IF_SAFE
140 #  define PNG_HANDLE_CHUNK_IF_SAFE      2
141 #endif
142 
143 /* Utility to save typing/errors, the argument must be a name */
144 #define MEMZERO(var) ((void)memset(&var, 0, sizeof var))
145 
146 /* Example of using row callbacks to make a simple progress meter */
147 static int status_pass = 1;
148 static int status_dots_requested = 0;
149 static int status_dots = 1;
150 
151 static void PNGCBAPI
read_row_callback(png_structp png_ptr,png_uint_32 row_number,int pass)152 read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
153 {
154    if (png_ptr == NULL || row_number > PNG_UINT_31_MAX)
155       return;
156 
157    if (status_pass != pass)
158    {
159       fprintf(stdout, "\n Pass %d: ", pass);
160       status_pass = pass;
161       status_dots = 31;
162    }
163 
164    status_dots--;
165 
166    if (status_dots == 0)
167    {
168       fprintf(stdout, "\n         ");
169       status_dots=30;
170    }
171 
172    fprintf(stdout, "r");
173 }
174 
175 #ifdef PNG_WRITE_SUPPORTED
176 static void PNGCBAPI
write_row_callback(png_structp png_ptr,png_uint_32 row_number,int pass)177 write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass)
178 {
179    if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7)
180       return;
181 
182    fprintf(stdout, "w");
183 }
184 #endif
185 
186 
187 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
188 /* Example of using user transform callback (we don't transform anything,
189  * but merely examine the row filters.  We set this to 256 rather than
190  * 5 in case illegal filter values are present.)
191  */
192 static png_uint_32 filters_used[256];
193 static void PNGCBAPI
count_filters(png_structp png_ptr,png_row_infop row_info,png_bytep data)194 count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data)
195 {
196    if (png_ptr != NULL && row_info != NULL)
197       ++filters_used[*(data - 1)];
198 }
199 #endif
200 
201 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
202 /* Example of using user transform callback (we don't transform anything,
203  * but merely count the zero samples)
204  */
205 
206 static png_uint_32 zero_samples;
207 
208 static void PNGCBAPI
count_zero_samples(png_structp png_ptr,png_row_infop row_info,png_bytep data)209 count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data)
210 {
211    png_bytep dp = data;
212    if (png_ptr == NULL)
213       return;
214 
215    /* Contents of row_info:
216     *  png_uint_32 width      width of row
217     *  png_uint_32 rowbytes   number of bytes in row
218     *  png_byte color_type    color type of pixels
219     *  png_byte bit_depth     bit depth of samples
220     *  png_byte channels      number of channels (1-4)
221     *  png_byte pixel_depth   bits per pixel (depth*channels)
222     */
223 
224     /* Counts the number of zero samples (or zero pixels if color_type is 3 */
225 
226     if (row_info->color_type == 0 || row_info->color_type == 3)
227     {
228        int pos = 0;
229        png_uint_32 n, nstop;
230 
231        for (n = 0, nstop=row_info->width; n<nstop; n++)
232        {
233           if (row_info->bit_depth == 1)
234           {
235              if (((*dp << pos++ ) & 0x80) == 0)
236                 zero_samples++;
237 
238              if (pos == 8)
239              {
240                 pos = 0;
241                 dp++;
242              }
243           }
244 
245           if (row_info->bit_depth == 2)
246           {
247              if (((*dp << (pos+=2)) & 0xc0) == 0)
248                 zero_samples++;
249 
250              if (pos == 8)
251              {
252                 pos = 0;
253                 dp++;
254              }
255           }
256 
257           if (row_info->bit_depth == 4)
258           {
259              if (((*dp << (pos+=4)) & 0xf0) == 0)
260                 zero_samples++;
261 
262              if (pos == 8)
263              {
264                 pos = 0;
265                 dp++;
266              }
267           }
268 
269           if (row_info->bit_depth == 8)
270              if (*dp++ == 0)
271                 zero_samples++;
272 
273           if (row_info->bit_depth == 16)
274           {
275              if ((*dp | *(dp+1)) == 0)
276                 zero_samples++;
277              dp+=2;
278           }
279        }
280     }
281     else /* Other color types */
282     {
283        png_uint_32 n, nstop;
284        int channel;
285        int color_channels = row_info->channels;
286        if (row_info->color_type > 3)
287           color_channels--;
288 
289        for (n = 0, nstop=row_info->width; n<nstop; n++)
290        {
291           for (channel = 0; channel < color_channels; channel++)
292           {
293              if (row_info->bit_depth == 8)
294                 if (*dp++ == 0)
295                    zero_samples++;
296 
297              if (row_info->bit_depth == 16)
298              {
299                 if ((*dp | *(dp+1)) == 0)
300                    zero_samples++;
301 
302                 dp+=2;
303              }
304           }
305           if (row_info->color_type > 3)
306           {
307              dp++;
308              if (row_info->bit_depth == 16)
309                 dp++;
310           }
311        }
312     }
313 }
314 #endif /* WRITE_USER_TRANSFORM */
315 
316 #ifndef PNG_STDIO_SUPPORTED
317 /* START of code to validate stdio-free compilation */
318 /* These copies of the default read/write functions come from pngrio.c and
319  * pngwio.c.  They allow "don't include stdio" testing of the library.
320  * This is the function that does the actual reading of data.  If you are
321  * not reading from a standard C stream, you should create a replacement
322  * read_data function and use it at run time with png_set_read_fn(), rather
323  * than changing the library.
324  */
325 
326 #ifdef PNG_IO_STATE_SUPPORTED
327 void
328 pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
329    png_uint_32 io_op);
330 void
pngtest_check_io_state(png_structp png_ptr,png_size_t data_length,png_uint_32 io_op)331 pngtest_check_io_state(png_structp png_ptr, png_size_t data_length,
332    png_uint_32 io_op)
333 {
334    png_uint_32 io_state = png_get_io_state(png_ptr);
335    int err = 0;
336 
337    /* Check if the current operation (reading / writing) is as expected. */
338    if ((io_state & PNG_IO_MASK_OP) != io_op)
339       png_error(png_ptr, "Incorrect operation in I/O state");
340 
341    /* Check if the buffer size specific to the current location
342     * (file signature / header / data / crc) is as expected.
343     */
344    switch (io_state & PNG_IO_MASK_LOC)
345    {
346    case PNG_IO_SIGNATURE:
347       if (data_length > 8)
348          err = 1;
349       break;
350    case PNG_IO_CHUNK_HDR:
351       if (data_length != 8)
352          err = 1;
353       break;
354    case PNG_IO_CHUNK_DATA:
355       break;  /* no restrictions here */
356    case PNG_IO_CHUNK_CRC:
357       if (data_length != 4)
358          err = 1;
359       break;
360    default:
361       err = 1;  /* uninitialized */
362    }
363    if (err != 0)
364       png_error(png_ptr, "Bad I/O state or buffer size");
365 }
366 #endif
367 
368 static void PNGCBAPI
pngtest_read_data(png_structp png_ptr,png_bytep data,png_size_t length)369 pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
370 {
371    png_size_t check = 0;
372    png_voidp io_ptr;
373 
374    /* fread() returns 0 on error, so it is OK to store this in a png_size_t
375     * instead of an int, which is what fread() actually returns.
376     */
377    io_ptr = png_get_io_ptr(png_ptr);
378    if (io_ptr != NULL)
379    {
380       check = fread(data, 1, length, (png_FILE_p)io_ptr);
381    }
382 
383    if (check != length)
384    {
385       png_error(png_ptr, "Read Error");
386    }
387 
388 #ifdef PNG_IO_STATE_SUPPORTED
389    pngtest_check_io_state(png_ptr, length, PNG_IO_READING);
390 #endif
391 }
392 
393 #ifdef PNG_WRITE_FLUSH_SUPPORTED
394 static void PNGCBAPI
pngtest_flush(png_structp png_ptr)395 pngtest_flush(png_structp png_ptr)
396 {
397    /* Do nothing; fflush() is said to be just a waste of energy. */
398    PNG_UNUSED(png_ptr)   /* Stifle compiler warning */
399 }
400 #endif
401 
402 /* This is the function that does the actual writing of data.  If you are
403  * not writing to a standard C stream, you should create a replacement
404  * write_data function and use it at run time with png_set_write_fn(), rather
405  * than changing the library.
406  */
407 static void PNGCBAPI
pngtest_write_data(png_structp png_ptr,png_bytep data,png_size_t length)408 pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
409 {
410    png_size_t check;
411 
412    check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr));
413 
414    if (check != length)
415    {
416       png_error(png_ptr, "Write Error");
417    }
418 
419 #ifdef PNG_IO_STATE_SUPPORTED
420    pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
421 #endif
422 }
423 #endif /* !STDIO */
424 
425 /* This function is called when there is a warning, but the library thinks
426  * it can continue anyway.  Replacement functions don't have to do anything
427  * here if you don't want to.  In the default configuration, png_ptr is
428  * not used, but it is passed in case it may be useful.
429  */
430 typedef struct
431 {
432    PNG_CONST char *file_name;
433 }  pngtest_error_parameters;
434 
435 static void PNGCBAPI
pngtest_warning(png_structp png_ptr,png_const_charp message)436 pngtest_warning(png_structp png_ptr, png_const_charp message)
437 {
438    PNG_CONST char *name = "UNKNOWN (ERROR!)";
439    pngtest_error_parameters *test =
440       (pngtest_error_parameters*)png_get_error_ptr(png_ptr);
441 
442    ++warning_count;
443 
444    if (test != NULL && test->file_name != NULL)
445       name = test->file_name;
446 
447    fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
448 }
449 
450 /* This is the default error handling function.  Note that replacements for
451  * this function MUST NOT RETURN, or the program will likely crash.  This
452  * function is used by default, or if the program supplies NULL for the
453  * error function pointer in png_set_error_fn().
454  */
455 static void PNGCBAPI
pngtest_error(png_structp png_ptr,png_const_charp message)456 pngtest_error(png_structp png_ptr, png_const_charp message)
457 {
458    ++error_count;
459 
460    pngtest_warning(png_ptr, message);
461    /* We can return because png_error calls the default handler, which is
462     * actually OK in this case.
463     */
464 }
465 
466 /* END of code to validate stdio-free compilation */
467 
468 /* START of code to validate memory allocation and deallocation */
469 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
470 
471 /* Allocate memory.  For reasonable files, size should never exceed
472  * 64K.  However, zlib may allocate more than 64K if you don't tell
473  * it not to.  See zconf.h and png.h for more information.  zlib does
474  * need to allocate exactly 64K, so whatever you call here must
475  * have the ability to do that.
476  *
477  * This piece of code can be compiled to validate max 64K allocations
478  * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
479  */
480 typedef struct memory_information
481 {
482    png_alloc_size_t          size;
483    png_voidp                 pointer;
484    struct memory_information *next;
485 } memory_information;
486 typedef memory_information *memory_infop;
487 
488 static memory_infop pinformation = NULL;
489 static int current_allocation = 0;
490 static int maximum_allocation = 0;
491 static int total_allocation = 0;
492 static int num_allocations = 0;
493 
494 png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr,
495     png_alloc_size_t size));
496 void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr));
497 
498 png_voidp
png_debug_malloc(png_structp png_ptr,png_alloc_size_t size)499 PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size)
500 {
501 
502    /* png_malloc has already tested for NULL; png_create_struct calls
503     * png_debug_malloc directly, with png_ptr == NULL which is OK
504     */
505 
506    if (size == 0)
507       return (NULL);
508 
509    /* This calls the library allocator twice, once to get the requested
510       buffer and once to get a new free list entry. */
511    {
512       /* Disable malloc_fn and free_fn */
513       memory_infop pinfo;
514       png_set_mem_fn(png_ptr, NULL, NULL, NULL);
515       pinfo = (memory_infop)png_malloc(png_ptr,
516          (sizeof *pinfo));
517       pinfo->size = size;
518       current_allocation += size;
519       total_allocation += size;
520       num_allocations ++;
521 
522       if (current_allocation > maximum_allocation)
523          maximum_allocation = current_allocation;
524 
525       pinfo->pointer = png_malloc(png_ptr, size);
526       /* Restore malloc_fn and free_fn */
527 
528       png_set_mem_fn(png_ptr,
529           NULL, png_debug_malloc, png_debug_free);
530 
531       if (size != 0 && pinfo->pointer == NULL)
532       {
533          current_allocation -= size;
534          total_allocation -= size;
535          png_error(png_ptr,
536            "out of memory in pngtest->png_debug_malloc");
537       }
538 
539       pinfo->next = pinformation;
540       pinformation = pinfo;
541       /* Make sure the caller isn't assuming zeroed memory. */
542       memset(pinfo->pointer, 0xdd, pinfo->size);
543 
544       if (verbose != 0)
545          printf("png_malloc %lu bytes at %p\n", (unsigned long)size,
546             pinfo->pointer);
547 
548       return (png_voidp)(pinfo->pointer);
549    }
550 }
551 
552 /* Free a pointer.  It is removed from the list at the same time. */
553 void PNGCBAPI
png_debug_free(png_structp png_ptr,png_voidp ptr)554 png_debug_free(png_structp png_ptr, png_voidp ptr)
555 {
556    if (png_ptr == NULL)
557       fprintf(STDERR, "NULL pointer to png_debug_free.\n");
558 
559    if (ptr == 0)
560    {
561 #if 0 /* This happens all the time. */
562       fprintf(STDERR, "WARNING: freeing NULL pointer\n");
563 #endif
564       return;
565    }
566 
567    /* Unlink the element from the list. */
568    if (pinformation != NULL)
569    {
570       memory_infop *ppinfo = &pinformation;
571 
572       for (;;)
573       {
574          memory_infop pinfo = *ppinfo;
575 
576          if (pinfo->pointer == ptr)
577          {
578             *ppinfo = pinfo->next;
579             current_allocation -= pinfo->size;
580             if (current_allocation < 0)
581                fprintf(STDERR, "Duplicate free of memory\n");
582             /* We must free the list element too, but first kill
583                the memory that is to be freed. */
584             memset(ptr, 0x55, pinfo->size);
585             free(pinfo);
586             pinfo = NULL;
587             break;
588          }
589 
590          if (pinfo->next == NULL)
591          {
592             fprintf(STDERR, "Pointer %p not found\n", ptr);
593             break;
594          }
595 
596          ppinfo = &pinfo->next;
597       }
598    }
599 
600    /* Finally free the data. */
601    if (verbose != 0)
602       printf("Freeing %p\n", ptr);
603 
604    if (ptr != NULL)
605       free(ptr);
606    ptr = NULL;
607 }
608 #endif /* USER_MEM && DEBUG */
609 /* END of code to test memory allocation/deallocation */
610 
611 
612 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
613 /* Demonstration of user chunk support of the sTER and vpAg chunks */
614 
615 /* (sTER is a public chunk not yet known by libpng.  vpAg is a private
616 chunk used in ImageMagick to store "virtual page" size).  */
617 
618 static struct user_chunk_data
619 {
620    png_const_infop info_ptr;
621    png_uint_32     vpAg_width, vpAg_height;
622    png_byte        vpAg_units;
623    png_byte        sTER_mode;
624    int             location[2];
625 }
626 user_chunk_data;
627 
628 /* Used for location and order; zero means nothing. */
629 #define have_sTER   0x01
630 #define have_vpAg   0x02
631 #define before_PLTE 0x10
632 #define before_IDAT 0x20
633 #define after_IDAT  0x40
634 
635 static void
init_callback_info(png_const_infop info_ptr)636 init_callback_info(png_const_infop info_ptr)
637 {
638    MEMZERO(user_chunk_data);
639    user_chunk_data.info_ptr = info_ptr;
640 }
641 
642 static int
set_location(png_structp png_ptr,struct user_chunk_data * data,int what)643 set_location(png_structp png_ptr, struct user_chunk_data *data, int what)
644 {
645    int location;
646 
647    if ((data->location[0] & what) != 0 || (data->location[1] & what) != 0)
648       return 0; /* already have one of these */
649 
650    /* Find where we are (the code below zeroes info_ptr to indicate that the
651     * chunks before the first IDAT have been read.)
652     */
653    if (data->info_ptr == NULL) /* after IDAT */
654       location = what | after_IDAT;
655 
656    else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0)
657       location = what | before_IDAT;
658 
659    else
660       location = what | before_PLTE;
661 
662    if (data->location[0] == 0)
663       data->location[0] = location;
664 
665    else
666       data->location[1] = location;
667 
668    return 1; /* handled */
669 }
670 
671 static int PNGCBAPI
read_user_chunk_callback(png_struct * png_ptr,png_unknown_chunkp chunk)672 read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk)
673 {
674    struct user_chunk_data *my_user_chunk_data =
675       (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr);
676 
677    if (my_user_chunk_data == NULL)
678       png_error(png_ptr, "lost user chunk pointer");
679 
680    /* Return one of the following:
681     *    return (-n);  chunk had an error
682     *    return (0);  did not recognize
683     *    return (n);  success
684     *
685     * The unknown chunk structure contains the chunk data:
686     * png_byte name[5];
687     * png_byte *data;
688     * png_size_t size;
689     *
690     * Note that libpng has already taken care of the CRC handling.
691     */
692 
693    if (chunk->name[0] == 115 && chunk->name[1] ==  84 &&     /* s  T */
694        chunk->name[2] ==  69 && chunk->name[3] ==  82)       /* E  R */
695       {
696          /* Found sTER chunk */
697          if (chunk->size != 1)
698             return (-1); /* Error return */
699 
700          if (chunk->data[0] != 0 && chunk->data[0] != 1)
701             return (-1);  /* Invalid mode */
702 
703          if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0)
704          {
705             my_user_chunk_data->sTER_mode=chunk->data[0];
706             return (1);
707          }
708 
709          else
710             return (0); /* duplicate sTER - give it to libpng */
711       }
712 
713    if (chunk->name[0] != 118 || chunk->name[1] != 112 ||    /* v  p */
714        chunk->name[2] !=  65 || chunk->name[3] != 103)      /* A  g */
715       return (0); /* Did not recognize */
716 
717    /* Found ImageMagick vpAg chunk */
718 
719    if (chunk->size != 9)
720       return (-1); /* Error return */
721 
722    if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0)
723       return (0);  /* duplicate vpAg */
724 
725    my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data);
726    my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4);
727    my_user_chunk_data->vpAg_units = chunk->data[8];
728 
729    return (1);
730 }
731 
732 #ifdef PNG_WRITE_SUPPORTED
733 static void
write_sTER_chunk(png_structp write_ptr)734 write_sTER_chunk(png_structp write_ptr)
735 {
736    png_byte sTER[5] = {115,  84,  69,  82, '\0'};
737 
738    if (verbose != 0)
739       fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode);
740 
741    png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1);
742 }
743 
744 static void
write_vpAg_chunk(png_structp write_ptr)745 write_vpAg_chunk(png_structp write_ptr)
746 {
747    png_byte vpAg[5] = {118, 112,  65, 103, '\0'};
748 
749    png_byte vpag_chunk_data[9];
750 
751    if (verbose != 0)
752       fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n",
753         (unsigned long)user_chunk_data.vpAg_width,
754         (unsigned long)user_chunk_data.vpAg_height,
755         user_chunk_data.vpAg_units);
756 
757    png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width);
758    png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height);
759    vpag_chunk_data[8] = user_chunk_data.vpAg_units;
760    png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9);
761 }
762 
763 static void
write_chunks(png_structp write_ptr,int location)764 write_chunks(png_structp write_ptr, int location)
765 {
766    int i;
767 
768    /* Notice that this preserves the original chunk order, however chunks
769     * intercepted by the callback will be written *after* chunks passed to
770     * libpng.  This will actually reverse a pair of sTER chunks or a pair of
771     * vpAg chunks, resulting in an error later.  This is not worth worrying
772     * about - the chunks should not be duplicated!
773     */
774    for (i=0; i<2; ++i)
775    {
776       if (user_chunk_data.location[i] == (location | have_sTER))
777          write_sTER_chunk(write_ptr);
778 
779       else if (user_chunk_data.location[i] == (location | have_vpAg))
780          write_vpAg_chunk(write_ptr);
781    }
782 }
783 #endif /* WRITE */
784 #else /* !READ_USER_CHUNKS */
785 #  define write_chunks(pp,loc) ((void)0)
786 #endif
787 /* END of code to demonstrate user chunk support */
788 
789 /* START of code to check that libpng has the required text support; this only
790  * checks for the write support because if read support is missing the chunk
791  * will simply not be reported back to pngtest.
792  */
793 #ifdef PNG_TEXT_SUPPORTED
794 static void
pngtest_check_text_support(png_const_structp png_ptr,png_textp text_ptr,int num_text)795 pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr,
796    int num_text)
797 {
798    while (num_text > 0)
799    {
800       switch (text_ptr[--num_text].compression)
801       {
802          case PNG_TEXT_COMPRESSION_NONE:
803             break;
804 
805          case PNG_TEXT_COMPRESSION_zTXt:
806 #           ifndef PNG_WRITE_zTXt_SUPPORTED
807                ++unsupported_chunks;
808 #           endif
809             break;
810 
811          case PNG_ITXT_COMPRESSION_NONE:
812          case PNG_ITXT_COMPRESSION_zTXt:
813 #           ifndef PNG_WRITE_iTXt_SUPPORTED
814                ++unsupported_chunks;
815 #           endif
816             break;
817 
818          default:
819             /* This is an error */
820             png_error(png_ptr, "invalid text chunk compression field");
821             break;
822       }
823    }
824 }
825 #endif
826 /* END of code to check that libpng has the required text support */
827 
828 /* Test one file */
829 static int
test_one_file(PNG_CONST char * inname,PNG_CONST char * outname)830 test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
831 {
832    static png_FILE_p fpin;
833    static png_FILE_p fpout;  /* "static" prevents setjmp corruption */
834    pngtest_error_parameters error_parameters;
835    png_structp read_ptr;
836    png_infop read_info_ptr, end_info_ptr;
837 #ifdef PNG_WRITE_SUPPORTED
838    png_structp write_ptr;
839    png_infop write_info_ptr;
840    png_infop write_end_info_ptr;
841    int interlace_preserved = 1;
842 #else
843    png_structp write_ptr = NULL;
844    png_infop write_info_ptr = NULL;
845    png_infop write_end_info_ptr = NULL;
846 #endif
847    png_bytep row_buf;
848    png_uint_32 y;
849    png_uint_32 width, height;
850    int num_pass = 1, pass;
851    int bit_depth, color_type;
852 
853    row_buf = NULL;
854    error_parameters.file_name = inname;
855 
856    if ((fpin = fopen(inname, "rb")) == NULL)
857    {
858       fprintf(STDERR, "Could not find input file %s\n", inname);
859       return (1);
860    }
861 
862    if ((fpout = fopen(outname, "wb")) == NULL)
863    {
864       fprintf(STDERR, "Could not open output file %s\n", outname);
865       FCLOSE(fpin);
866       return (1);
867    }
868 
869    pngtest_debug("Allocating read and write structures");
870 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
871    read_ptr =
872       png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL,
873       NULL, NULL, NULL, png_debug_malloc, png_debug_free);
874 #else
875    read_ptr =
876       png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
877 #endif
878    png_set_error_fn(read_ptr, &error_parameters, pngtest_error,
879       pngtest_warning);
880 
881 #ifdef PNG_WRITE_SUPPORTED
882 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
883    write_ptr =
884       png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL,
885       NULL, NULL, NULL, png_debug_malloc, png_debug_free);
886 #else
887    write_ptr =
888       png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
889 #endif
890    png_set_error_fn(write_ptr, &error_parameters, pngtest_error,
891       pngtest_warning);
892 #endif
893    pngtest_debug("Allocating read_info, write_info and end_info structures");
894    read_info_ptr = png_create_info_struct(read_ptr);
895    end_info_ptr = png_create_info_struct(read_ptr);
896 #ifdef PNG_WRITE_SUPPORTED
897    write_info_ptr = png_create_info_struct(write_ptr);
898    write_end_info_ptr = png_create_info_struct(write_ptr);
899 #endif
900 
901 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
902    init_callback_info(read_info_ptr);
903    png_set_read_user_chunk_fn(read_ptr, &user_chunk_data,
904      read_user_chunk_callback);
905 #endif
906 
907 #ifdef PNG_SETJMP_SUPPORTED
908    pngtest_debug("Setting jmpbuf for read struct");
909    if (setjmp(png_jmpbuf(read_ptr)))
910    {
911       fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname);
912       png_free(read_ptr, row_buf);
913       row_buf = NULL;
914       png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
915 #ifdef PNG_WRITE_SUPPORTED
916       png_destroy_info_struct(write_ptr, &write_end_info_ptr);
917       png_destroy_write_struct(&write_ptr, &write_info_ptr);
918 #endif
919       FCLOSE(fpin);
920       FCLOSE(fpout);
921       return (1);
922    }
923 
924 #ifdef PNG_WRITE_SUPPORTED
925    pngtest_debug("Setting jmpbuf for write struct");
926 
927    if (setjmp(png_jmpbuf(write_ptr)))
928    {
929       fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname);
930       png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
931       png_destroy_info_struct(write_ptr, &write_end_info_ptr);
932 #ifdef PNG_WRITE_SUPPORTED
933       png_destroy_write_struct(&write_ptr, &write_info_ptr);
934 #endif
935       FCLOSE(fpin);
936       FCLOSE(fpout);
937       return (1);
938    }
939 #endif
940 #endif
941 
942    if (strict != 0)
943    {
944       /* Treat png_benign_error() as errors on read */
945       png_set_benign_errors(read_ptr, 0);
946 
947 #ifdef PNG_WRITE_SUPPORTED
948       /* Treat them as errors on write */
949       png_set_benign_errors(write_ptr, 0);
950 #endif
951 
952       /* if strict is not set, then app warnings and errors are treated as
953        * warnings in release builds, but not in unstable builds; this can be
954        * changed with '--relaxed'.
955        */
956    }
957 
958    else if (relaxed != 0)
959    {
960       /* Allow application (pngtest) errors and warnings to pass */
961       png_set_benign_errors(read_ptr, 1);
962 
963 #ifdef PNG_WRITE_SUPPORTED
964       png_set_benign_errors(write_ptr, 1);
965 #endif
966    }
967 
968    pngtest_debug("Initializing input and output streams");
969 #ifdef PNG_STDIO_SUPPORTED
970    png_init_io(read_ptr, fpin);
971 #  ifdef PNG_WRITE_SUPPORTED
972    png_init_io(write_ptr, fpout);
973 #  endif
974 #else
975    png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data);
976 #  ifdef PNG_WRITE_SUPPORTED
977    png_set_write_fn(write_ptr, (png_voidp)fpout,  pngtest_write_data,
978 #    ifdef PNG_WRITE_FLUSH_SUPPORTED
979       pngtest_flush);
980 #    else
981       NULL);
982 #    endif
983 #  endif
984 #endif
985 
986    if (status_dots_requested == 1)
987    {
988 #ifdef PNG_WRITE_SUPPORTED
989       png_set_write_status_fn(write_ptr, write_row_callback);
990 #endif
991       png_set_read_status_fn(read_ptr, read_row_callback);
992    }
993 
994    else
995    {
996 #ifdef PNG_WRITE_SUPPORTED
997       png_set_write_status_fn(write_ptr, NULL);
998 #endif
999       png_set_read_status_fn(read_ptr, NULL);
1000    }
1001 
1002 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1003    {
1004       int i;
1005 
1006       for (i = 0; i<256; i++)
1007          filters_used[i] = 0;
1008 
1009       png_set_read_user_transform_fn(read_ptr, count_filters);
1010    }
1011 #endif
1012 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1013    zero_samples = 0;
1014    png_set_write_user_transform_fn(write_ptr, count_zero_samples);
1015 #endif
1016 
1017 #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
1018    /* Preserve all the unknown chunks, if possible.  If this is disabled then,
1019     * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use
1020     * libpng to *save* the unknown chunks on read (because we can't switch the
1021     * save option on!)
1022     *
1023     * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all
1024     * unknown chunks and write will write them all.
1025     */
1026 #ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
1027    png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1028       NULL, 0);
1029 #endif
1030 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1031    png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
1032       NULL, 0);
1033 #endif
1034 #endif
1035 
1036    pngtest_debug("Reading info struct");
1037    png_read_info(read_ptr, read_info_ptr);
1038 
1039 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1040    /* This is a bit of a hack; there is no obvious way in the callback function
1041     * to determine that the chunks before the first IDAT have been read, so
1042     * remove the info_ptr (which is only used to determine position relative to
1043     * PLTE) here to indicate that we are after the IDAT.
1044     */
1045    user_chunk_data.info_ptr = NULL;
1046 #endif
1047 
1048    pngtest_debug("Transferring info struct");
1049    {
1050       int interlace_type, compression_type, filter_type;
1051 
1052       if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth,
1053           &color_type, &interlace_type, &compression_type, &filter_type) != 0)
1054       {
1055          png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth,
1056             color_type, interlace_type, compression_type, filter_type);
1057 #ifndef PNG_READ_INTERLACING_SUPPORTED
1058          /* num_pass will not be set below, set it here if the image is
1059           * interlaced: what happens is that write interlacing is *not* turned
1060           * on an the partial interlaced rows are written directly.
1061           */
1062          switch (interlace_type)
1063          {
1064             case PNG_INTERLACE_NONE:
1065                num_pass = 1;
1066                break;
1067 
1068             case PNG_INTERLACE_ADAM7:
1069                num_pass = 7;
1070                 break;
1071 
1072             default:
1073                 png_error(read_ptr, "invalid interlace type");
1074                 /*NOT REACHED*/
1075          }
1076 #endif
1077       }
1078    }
1079 #ifdef PNG_FIXED_POINT_SUPPORTED
1080 #ifdef PNG_cHRM_SUPPORTED
1081    {
1082       png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1083          blue_y;
1084 
1085       if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y,
1086          &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1087       {
1088          png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x,
1089             red_y, green_x, green_y, blue_x, blue_y);
1090       }
1091    }
1092 #endif
1093 #ifdef PNG_gAMA_SUPPORTED
1094    {
1095       png_fixed_point gamma;
1096 
1097       if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0)
1098          png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma);
1099    }
1100 #endif
1101 #else /* Use floating point versions */
1102 #ifdef PNG_FLOATING_POINT_SUPPORTED
1103 #ifdef PNG_cHRM_SUPPORTED
1104    {
1105       double white_x, white_y, red_x, red_y, green_x, green_y, blue_x,
1106          blue_y;
1107 
1108       if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x,
1109          &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0)
1110       {
1111          png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x,
1112             red_y, green_x, green_y, blue_x, blue_y);
1113       }
1114    }
1115 #endif
1116 #ifdef PNG_gAMA_SUPPORTED
1117    {
1118       double gamma;
1119 
1120       if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0)
1121          png_set_gAMA(write_ptr, write_info_ptr, gamma);
1122    }
1123 #endif
1124 #endif /* Floating point */
1125 #endif /* Fixed point */
1126 #ifdef PNG_iCCP_SUPPORTED
1127    {
1128       png_charp name;
1129       png_bytep profile;
1130       png_uint_32 proflen;
1131       int compression_type;
1132 
1133       if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type,
1134                       &profile, &proflen) != 0)
1135       {
1136          png_set_iCCP(write_ptr, write_info_ptr, name, compression_type,
1137                       profile, proflen);
1138       }
1139    }
1140 #endif
1141 #ifdef PNG_sRGB_SUPPORTED
1142    {
1143       int intent;
1144 
1145       if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0)
1146          png_set_sRGB(write_ptr, write_info_ptr, intent);
1147    }
1148 #endif
1149    {
1150       png_colorp palette;
1151       int num_palette;
1152 
1153       if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0)
1154          png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette);
1155    }
1156 #ifdef PNG_bKGD_SUPPORTED
1157    {
1158       png_color_16p background;
1159 
1160       if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0)
1161       {
1162          png_set_bKGD(write_ptr, write_info_ptr, background);
1163       }
1164    }
1165 #endif
1166 #ifdef PNG_hIST_SUPPORTED
1167    {
1168       png_uint_16p hist;
1169 
1170       if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0)
1171          png_set_hIST(write_ptr, write_info_ptr, hist);
1172    }
1173 #endif
1174 #ifdef PNG_oFFs_SUPPORTED
1175    {
1176       png_int_32 offset_x, offset_y;
1177       int unit_type;
1178 
1179       if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y,
1180           &unit_type) != 0)
1181       {
1182          png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type);
1183       }
1184    }
1185 #endif
1186 #ifdef PNG_pCAL_SUPPORTED
1187    {
1188       png_charp purpose, units;
1189       png_charpp params;
1190       png_int_32 X0, X1;
1191       int type, nparams;
1192 
1193       if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type,
1194          &nparams, &units, &params) != 0)
1195       {
1196          png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type,
1197             nparams, units, params);
1198       }
1199    }
1200 #endif
1201 #ifdef PNG_pHYs_SUPPORTED
1202    {
1203       png_uint_32 res_x, res_y;
1204       int unit_type;
1205 
1206       if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y,
1207           &unit_type) != 0)
1208          png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type);
1209    }
1210 #endif
1211 #ifdef PNG_sBIT_SUPPORTED
1212    {
1213       png_color_8p sig_bit;
1214 
1215       if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0)
1216          png_set_sBIT(write_ptr, write_info_ptr, sig_bit);
1217    }
1218 #endif
1219 #ifdef PNG_sCAL_SUPPORTED
1220 #if defined(PNG_FLOATING_POINT_SUPPORTED) && \
1221    defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
1222    {
1223       int unit;
1224       double scal_width, scal_height;
1225 
1226       if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width,
1227          &scal_height) != 0)
1228       {
1229          png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height);
1230       }
1231    }
1232 #else
1233 #ifdef PNG_FIXED_POINT_SUPPORTED
1234    {
1235       int unit;
1236       png_charp scal_width, scal_height;
1237 
1238       if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width,
1239           &scal_height) != 0)
1240       {
1241          png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width,
1242              scal_height);
1243       }
1244    }
1245 #endif
1246 #endif
1247 #endif
1248 #ifdef PNG_TEXT_SUPPORTED
1249    {
1250       png_textp text_ptr;
1251       int num_text;
1252 
1253       if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0)
1254       {
1255          pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1256 
1257          pngtest_check_text_support(read_ptr, text_ptr, num_text);
1258 
1259          if (verbose != 0)
1260          {
1261             int i;
1262 
1263             printf("\n");
1264             for (i=0; i<num_text; i++)
1265             {
1266                printf("   Text compression[%d]=%d\n",
1267                      i, text_ptr[i].compression);
1268             }
1269          }
1270 
1271          png_set_text(write_ptr, write_info_ptr, text_ptr, num_text);
1272       }
1273    }
1274 #endif
1275 #ifdef PNG_tIME_SUPPORTED
1276    {
1277       png_timep mod_time;
1278 
1279       if (png_get_tIME(read_ptr, read_info_ptr, &mod_time) != 0)
1280       {
1281          png_set_tIME(write_ptr, write_info_ptr, mod_time);
1282 #ifdef PNG_TIME_RFC1123_SUPPORTED
1283          if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1284             tIME_string[(sizeof tIME_string) - 1] = '\0';
1285 
1286          else
1287          {
1288             strncpy(tIME_string, "*** invalid time ***", (sizeof tIME_string));
1289             tIME_string[(sizeof tIME_string) - 1] = '\0';
1290          }
1291 
1292          tIME_chunk_present++;
1293 #endif /* TIME_RFC1123 */
1294       }
1295    }
1296 #endif
1297 #ifdef PNG_tRNS_SUPPORTED
1298    {
1299       png_bytep trans_alpha;
1300       int num_trans;
1301       png_color_16p trans_color;
1302 
1303       if (png_get_tRNS(read_ptr, read_info_ptr, &trans_alpha, &num_trans,
1304          &trans_color) != 0)
1305       {
1306          int sample_max = (1 << bit_depth);
1307          /* libpng doesn't reject a tRNS chunk with out-of-range samples */
1308          if (!((color_type == PNG_COLOR_TYPE_GRAY &&
1309              (int)trans_color->gray > sample_max) ||
1310              (color_type == PNG_COLOR_TYPE_RGB &&
1311              ((int)trans_color->red > sample_max ||
1312              (int)trans_color->green > sample_max ||
1313              (int)trans_color->blue > sample_max))))
1314             png_set_tRNS(write_ptr, write_info_ptr, trans_alpha, num_trans,
1315                trans_color);
1316       }
1317    }
1318 #endif
1319 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1320    {
1321       png_unknown_chunkp unknowns;
1322       int num_unknowns = png_get_unknown_chunks(read_ptr, read_info_ptr,
1323          &unknowns);
1324 
1325       if (num_unknowns != 0)
1326       {
1327          png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns,
1328            num_unknowns);
1329 #if PNG_LIBPNG_VER < 10600
1330          /* Copy the locations from the read_info_ptr.  The automatically
1331           * generated locations in write_end_info_ptr are wrong prior to 1.6.0
1332           * because they are reset from the write pointer (removed in 1.6.0).
1333           */
1334          {
1335             int i;
1336             for (i = 0; i < num_unknowns; i++)
1337               png_set_unknown_chunk_location(write_ptr, write_info_ptr, i,
1338                 unknowns[i].location);
1339          }
1340 #endif
1341       }
1342    }
1343 #endif
1344 
1345 #ifdef PNG_WRITE_SUPPORTED
1346    pngtest_debug("Writing info struct");
1347 
1348    /* Write the info in two steps so that if we write the 'unknown' chunks here
1349     * they go to the correct place.
1350     */
1351    png_write_info_before_PLTE(write_ptr, write_info_ptr);
1352 
1353    write_chunks(write_ptr, before_PLTE); /* before PLTE */
1354 
1355    png_write_info(write_ptr, write_info_ptr);
1356 
1357    write_chunks(write_ptr, before_IDAT); /* after PLTE */
1358 #endif
1359 
1360 #ifdef SINGLE_ROWBUF_ALLOC
1361    pngtest_debug("Allocating row buffer...");
1362    row_buf = (png_bytep)png_malloc(read_ptr,
1363       png_get_rowbytes(read_ptr, read_info_ptr));
1364 
1365    pngtest_debug1("\t0x%08lx", (unsigned long)row_buf);
1366 #endif /* SINGLE_ROWBUF_ALLOC */
1367    pngtest_debug("Writing row data");
1368 
1369 #ifdef PNG_READ_INTERLACING_SUPPORTED
1370    num_pass = png_set_interlace_handling(read_ptr);
1371    if (png_set_interlace_handling(write_ptr) != num_pass)
1372       png_error(write_ptr, "png_set_interlace_handling: inconsistent num_pass");
1373 #endif
1374 
1375 #ifdef PNGTEST_TIMING
1376    t_stop = (float)clock();
1377    t_misc += (t_stop - t_start);
1378    t_start = t_stop;
1379 #endif
1380    for (pass = 0; pass < num_pass; pass++)
1381    {
1382       pngtest_debug1("Writing row data for pass %d", pass);
1383       for (y = 0; y < height; y++)
1384       {
1385 #ifndef SINGLE_ROWBUF_ALLOC
1386          pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y);
1387 
1388          row_buf = (png_bytep)png_malloc(read_ptr,
1389             png_get_rowbytes(read_ptr, read_info_ptr));
1390 
1391          pngtest_debug2("\t0x%08lx (%lu bytes)", (unsigned long)row_buf,
1392             (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr));
1393 
1394 #endif /* !SINGLE_ROWBUF_ALLOC */
1395          png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1);
1396 
1397 #ifdef PNG_WRITE_SUPPORTED
1398 #ifdef PNGTEST_TIMING
1399          t_stop = (float)clock();
1400          t_decode += (t_stop - t_start);
1401          t_start = t_stop;
1402 #endif
1403          png_write_rows(write_ptr, (png_bytepp)&row_buf, 1);
1404 #ifdef PNGTEST_TIMING
1405          t_stop = (float)clock();
1406          t_encode += (t_stop - t_start);
1407          t_start = t_stop;
1408 #endif
1409 #endif /* WRITE */
1410 
1411 #ifndef SINGLE_ROWBUF_ALLOC
1412          pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y);
1413          png_free(read_ptr, row_buf);
1414          row_buf = NULL;
1415 #endif /* !SINGLE_ROWBUF_ALLOC */
1416       }
1417    }
1418 
1419 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1420 #  ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
1421       png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
1422 #  endif
1423 #  ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1424       png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
1425 #  endif
1426 #endif
1427 
1428    pngtest_debug("Reading and writing end_info data");
1429 
1430    png_read_end(read_ptr, end_info_ptr);
1431 #ifdef PNG_TEXT_SUPPORTED
1432    {
1433       png_textp text_ptr;
1434       int num_text;
1435 
1436       if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0)
1437       {
1438          pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text);
1439 
1440          pngtest_check_text_support(read_ptr, text_ptr, num_text);
1441 
1442          if (verbose != 0)
1443          {
1444             int i;
1445 
1446             printf("\n");
1447             for (i=0; i<num_text; i++)
1448             {
1449                printf("   Text compression[%d]=%d\n",
1450                      i, text_ptr[i].compression);
1451             }
1452          }
1453 
1454          png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text);
1455       }
1456    }
1457 #endif
1458 #ifdef PNG_tIME_SUPPORTED
1459    {
1460       png_timep mod_time;
1461 
1462       if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0)
1463       {
1464          png_set_tIME(write_ptr, write_end_info_ptr, mod_time);
1465 #ifdef PNG_TIME_RFC1123_SUPPORTED
1466          if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0)
1467             tIME_string[(sizeof tIME_string) - 1] = '\0';
1468 
1469          else
1470          {
1471             strncpy(tIME_string, "*** invalid time ***", sizeof tIME_string);
1472             tIME_string[(sizeof tIME_string)-1] = '\0';
1473          }
1474 
1475          tIME_chunk_present++;
1476 #endif /* TIME_RFC1123 */
1477       }
1478    }
1479 #endif
1480 #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
1481    {
1482       png_unknown_chunkp unknowns;
1483       int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr,
1484          &unknowns);
1485 
1486       if (num_unknowns != 0)
1487       {
1488          png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns,
1489            num_unknowns);
1490 #if PNG_LIBPNG_VER < 10600
1491          /* Copy the locations from the read_info_ptr.  The automatically
1492           * generated locations in write_end_info_ptr are wrong prior to 1.6.0
1493           * because they are reset from the write pointer (removed in 1.6.0).
1494           */
1495          {
1496             int i;
1497             for (i = 0; i < num_unknowns; i++)
1498               png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i,
1499                 unknowns[i].location);
1500          }
1501 #endif
1502       }
1503    }
1504 #endif
1505 
1506 #ifdef PNG_WRITE_SUPPORTED
1507 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
1508    /* Normally one would use Z_DEFAULT_STRATEGY for text compression.
1509     * This is here just to make pngtest replicate the results from libpng
1510     * versions prior to 1.5.4, and to test this new API.
1511     */
1512    png_set_text_compression_strategy(write_ptr, Z_FILTERED);
1513 #endif
1514 
1515    /* When the unknown vpAg/sTER chunks are written by pngtest the only way to
1516     * do it is to write them *before* calling png_write_end.  When unknown
1517     * chunks are written by libpng, however, they are written just before IEND.
1518     * There seems to be no way round this, however vpAg/sTER are not expected
1519     * after IDAT.
1520     */
1521    write_chunks(write_ptr, after_IDAT);
1522 
1523    png_write_end(write_ptr, write_end_info_ptr);
1524 #endif
1525 
1526 #ifdef PNG_EASY_ACCESS_SUPPORTED
1527    if (verbose != 0)
1528    {
1529       png_uint_32 iwidth, iheight;
1530       iwidth = png_get_image_width(write_ptr, write_info_ptr);
1531       iheight = png_get_image_height(write_ptr, write_info_ptr);
1532       fprintf(STDERR, "\n Image width = %lu, height = %lu\n",
1533          (unsigned long)iwidth, (unsigned long)iheight);
1534    }
1535 #endif
1536 
1537    pngtest_debug("Destroying data structs");
1538 #ifdef SINGLE_ROWBUF_ALLOC
1539    pngtest_debug("destroying row_buf for read_ptr");
1540    png_free(read_ptr, row_buf);
1541    row_buf = NULL;
1542 #endif /* SINGLE_ROWBUF_ALLOC */
1543    pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr");
1544    png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
1545 #ifdef PNG_WRITE_SUPPORTED
1546    pngtest_debug("destroying write_end_info_ptr");
1547    png_destroy_info_struct(write_ptr, &write_end_info_ptr);
1548    pngtest_debug("destroying write_ptr, write_info_ptr");
1549    png_destroy_write_struct(&write_ptr, &write_info_ptr);
1550 #endif
1551    pngtest_debug("Destruction complete.");
1552 
1553    FCLOSE(fpin);
1554    FCLOSE(fpout);
1555 
1556    /* Summarize any warnings or errors and in 'strict' mode fail the test.
1557     * Unsupported chunks can result in warnings, in that case ignore the strict
1558     * setting, otherwise fail the test on warnings as well as errors.
1559     */
1560    if (error_count > 0)
1561    {
1562       /* We don't really expect to get here because of the setjmp handling
1563        * above, but this is safe.
1564        */
1565       fprintf(STDERR, "\n  %s: %d libpng errors found (%d warnings)",
1566          inname, error_count, warning_count);
1567 
1568       if (strict != 0)
1569          return (1);
1570    }
1571 
1572 #  ifdef PNG_WRITE_SUPPORTED
1573       /* If there we no write support nothing was written! */
1574       else if (unsupported_chunks > 0)
1575       {
1576          fprintf(STDERR, "\n  %s: unsupported chunks (%d)%s",
1577             inname, unsupported_chunks, strict ? ": IGNORED --strict!" : "");
1578       }
1579 #  endif
1580 
1581    else if (warning_count > 0)
1582    {
1583       fprintf(STDERR, "\n  %s: %d libpng warnings found",
1584          inname, warning_count);
1585 
1586       if (strict != 0)
1587          return (1);
1588    }
1589 
1590    pngtest_debug("Opening files for comparison");
1591    if ((fpin = fopen(inname, "rb")) == NULL)
1592    {
1593       fprintf(STDERR, "Could not find file %s\n", inname);
1594       return (1);
1595    }
1596 
1597    if ((fpout = fopen(outname, "rb")) == NULL)
1598    {
1599       fprintf(STDERR, "Could not find file %s\n", outname);
1600       FCLOSE(fpin);
1601       return (1);
1602    }
1603 
1604 #ifdef PNG_WRITE_SUPPORTED /* else nothing was written */
1605    if (interlace_preserved != 0) /* else the files will be changed */
1606    {
1607       for (;;)
1608       {
1609          static int wrote_question = 0;
1610          png_size_t num_in, num_out;
1611          char inbuf[256], outbuf[256];
1612 
1613          num_in = fread(inbuf, 1, sizeof inbuf, fpin);
1614          num_out = fread(outbuf, 1, sizeof outbuf, fpout);
1615 
1616          if (num_in != num_out)
1617          {
1618             fprintf(STDERR, "\nFiles %s and %s are of a different size\n",
1619                     inname, outname);
1620 
1621             if (wrote_question == 0 && unsupported_chunks == 0)
1622             {
1623                fprintf(STDERR,
1624          "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1625                  inname, PNG_ZBUF_SIZE);
1626                fprintf(STDERR,
1627                  "\n   filtering heuristic (libpng default), compression");
1628                fprintf(STDERR,
1629                  " level (zlib default),\n   and zlib version (%s)?\n\n",
1630                  ZLIB_VERSION);
1631                wrote_question = 1;
1632             }
1633 
1634             FCLOSE(fpin);
1635             FCLOSE(fpout);
1636 
1637             if (strict != 0 && unsupported_chunks == 0)
1638               return (1);
1639 
1640             else
1641               return (0);
1642          }
1643 
1644          if (num_in == 0)
1645             break;
1646 
1647          if (memcmp(inbuf, outbuf, num_in))
1648          {
1649             fprintf(STDERR, "\nFiles %s and %s are different\n", inname,
1650                outname);
1651 
1652             if (wrote_question == 0 && unsupported_chunks == 0)
1653             {
1654                fprintf(STDERR,
1655          "   Was %s written with the same maximum IDAT chunk size (%d bytes),",
1656                     inname, PNG_ZBUF_SIZE);
1657                fprintf(STDERR,
1658                  "\n   filtering heuristic (libpng default), compression");
1659                fprintf(STDERR,
1660                  " level (zlib default),\n   and zlib version (%s)?\n\n",
1661                  ZLIB_VERSION);
1662                wrote_question = 1;
1663             }
1664 
1665             FCLOSE(fpin);
1666             FCLOSE(fpout);
1667 
1668             /* NOTE: the unsupported_chunks escape is permitted here because
1669              * unsupported text chunk compression will result in the compression
1670              * mode being changed (to NONE) yet, in the test case, the result
1671              * can be exactly the same size!
1672              */
1673             if (strict != 0 && unsupported_chunks == 0)
1674               return (1);
1675 
1676             else
1677               return (0);
1678          }
1679       }
1680    }
1681 #endif /* WRITE */
1682 
1683    FCLOSE(fpin);
1684    FCLOSE(fpout);
1685 
1686    return (0);
1687 }
1688 
1689 /* Input and output filenames */
1690 #ifdef RISCOS
1691 static PNG_CONST char *inname = "pngtest/png";
1692 static PNG_CONST char *outname = "pngout/png";
1693 #else
1694 static PNG_CONST char *inname = "pngtest.png";
1695 static PNG_CONST char *outname = "pngout.png";
1696 #endif
1697 
1698 int
main(int argc,char * argv[])1699 main(int argc, char *argv[])
1700 {
1701    int multiple = 0;
1702    int ierror = 0;
1703 
1704    png_structp dummy_ptr;
1705 
1706    fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING);
1707    fprintf(STDERR, "   with zlib   version %s\n", ZLIB_VERSION);
1708    fprintf(STDERR, "%s", png_get_copyright(NULL));
1709    /* Show the version of libpng used in building the library */
1710    fprintf(STDERR, " library (%lu):%s",
1711       (unsigned long)png_access_version_number(),
1712       png_get_header_version(NULL));
1713 
1714    /* Show the version of libpng used in building the application */
1715    fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER,
1716       PNG_HEADER_VERSION_STRING);
1717 
1718    /* Do some consistency checking on the memory allocation settings, I'm
1719     * not sure this matters, but it is nice to know, the first of these
1720     * tests should be impossible because of the way the macros are set
1721     * in pngconf.h
1722     */
1723 #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
1724       fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n");
1725 #endif
1726    /* I think the following can happen. */
1727 #if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K)
1728       fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n");
1729 #endif
1730 
1731    if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING))
1732    {
1733       fprintf(STDERR,
1734          "Warning: versions are different between png.h and png.c\n");
1735       fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
1736       fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
1737       ++ierror;
1738    }
1739 
1740    if (argc > 1)
1741    {
1742       if (strcmp(argv[1], "-m") == 0)
1743       {
1744          multiple = 1;
1745          status_dots_requested = 0;
1746       }
1747 
1748       else if (strcmp(argv[1], "-mv") == 0 ||
1749                strcmp(argv[1], "-vm") == 0 )
1750       {
1751          multiple = 1;
1752          verbose = 1;
1753          status_dots_requested = 1;
1754       }
1755 
1756       else if (strcmp(argv[1], "-v") == 0)
1757       {
1758          verbose = 1;
1759          status_dots_requested = 1;
1760          inname = argv[2];
1761       }
1762 
1763       else if (strcmp(argv[1], "--strict") == 0)
1764       {
1765          status_dots_requested = 0;
1766          verbose = 1;
1767          inname = argv[2];
1768          strict++;
1769          relaxed = 0;
1770       }
1771 
1772       else if (strcmp(argv[1], "--relaxed") == 0)
1773       {
1774          status_dots_requested = 0;
1775          verbose = 1;
1776          inname = argv[2];
1777          strict = 0;
1778          relaxed++;
1779       }
1780 
1781       else
1782       {
1783          inname = argv[1];
1784          status_dots_requested = 0;
1785       }
1786    }
1787 
1788    if (multiple == 0 && argc == 3 + verbose)
1789      outname = argv[2 + verbose];
1790 
1791    if ((multiple == 0 && argc > 3 + verbose) ||
1792        (multiple != 0 && argc < 2))
1793    {
1794      fprintf(STDERR,
1795        "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n",
1796         argv[0], argv[0]);
1797      fprintf(STDERR,
1798        "  reads/writes one PNG file (without -m) or multiple files (-m)\n");
1799      fprintf(STDERR,
1800        "  with -m %s is used as a temporary file\n", outname);
1801      exit(1);
1802    }
1803 
1804    if (multiple != 0)
1805    {
1806       int i;
1807 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1808       int allocation_now = current_allocation;
1809 #endif
1810       for (i=2; i<argc; ++i)
1811       {
1812          int kerror;
1813          fprintf(STDERR, "\n Testing %s:", argv[i]);
1814 #if PNG_DEBUG > 0
1815          fprintf(STDERR, "\n");
1816 #endif
1817          kerror = test_one_file(argv[i], outname);
1818          if (kerror == 0)
1819          {
1820 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1821             int k;
1822 #endif
1823 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1824             fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1825                (unsigned long)zero_samples);
1826 #else
1827             fprintf(STDERR, " PASS\n");
1828 #endif
1829 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1830             for (k = 0; k<256; k++)
1831                if (filters_used[k] != 0)
1832                   fprintf(STDERR, " Filter %d was used %lu times\n",
1833                      k, (unsigned long)filters_used[k]);
1834 #endif
1835 #ifdef PNG_TIME_RFC1123_SUPPORTED
1836             if (tIME_chunk_present != 0)
1837                fprintf(STDERR, " tIME = %s\n", tIME_string);
1838 
1839             tIME_chunk_present = 0;
1840 #endif /* TIME_RFC1123 */
1841          }
1842 
1843          else
1844          {
1845             fprintf(STDERR, " FAIL\n");
1846             ierror += kerror;
1847          }
1848 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1849          if (allocation_now != current_allocation)
1850             fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1851                current_allocation - allocation_now);
1852 
1853          if (current_allocation != 0)
1854          {
1855             memory_infop pinfo = pinformation;
1856 
1857             fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1858                current_allocation);
1859 
1860             while (pinfo != NULL)
1861             {
1862                fprintf(STDERR, " %lu bytes at %p\n",
1863                  (unsigned long)pinfo->size,
1864                  pinfo->pointer);
1865                pinfo = pinfo->next;
1866             }
1867          }
1868 #endif
1869       }
1870 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1871          fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1872             current_allocation);
1873          fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1874             maximum_allocation);
1875          fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1876             total_allocation);
1877          fprintf(STDERR, "     Number of allocations: %10d\n",
1878             num_allocations);
1879 #endif
1880    }
1881 
1882    else
1883    {
1884       int i;
1885       for (i = 0; i<3; ++i)
1886       {
1887          int kerror;
1888 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1889          int allocation_now = current_allocation;
1890 #endif
1891          if (i == 1)
1892             status_dots_requested = 1;
1893 
1894          else if (verbose == 0)
1895             status_dots_requested = 0;
1896 
1897          if (i == 0 || verbose == 1 || ierror != 0)
1898          {
1899             fprintf(STDERR, "\n Testing %s:", inname);
1900 #if PNG_DEBUG > 0
1901             fprintf(STDERR, "\n");
1902 #endif
1903          }
1904 
1905          kerror = test_one_file(inname, outname);
1906 
1907          if (kerror == 0)
1908          {
1909             if (verbose == 1 || i == 2)
1910             {
1911 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1912                 int k;
1913 #endif
1914 #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED
1915                 fprintf(STDERR, "\n PASS (%lu zero samples)\n",
1916                    (unsigned long)zero_samples);
1917 #else
1918                 fprintf(STDERR, " PASS\n");
1919 #endif
1920 #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1921                 for (k = 0; k<256; k++)
1922                    if (filters_used[k] != 0)
1923                       fprintf(STDERR, " Filter %d was used %lu times\n",
1924                          k, (unsigned long)filters_used[k]);
1925 #endif
1926 #ifdef PNG_TIME_RFC1123_SUPPORTED
1927              if (tIME_chunk_present != 0)
1928                 fprintf(STDERR, " tIME = %s\n", tIME_string);
1929 #endif /* TIME_RFC1123 */
1930             }
1931          }
1932 
1933          else
1934          {
1935             if (verbose == 0 && i != 2)
1936             {
1937                fprintf(STDERR, "\n Testing %s:", inname);
1938 #if PNG_DEBUG > 0
1939                fprintf(STDERR, "\n");
1940 #endif
1941             }
1942 
1943             fprintf(STDERR, " FAIL\n");
1944             ierror += kerror;
1945          }
1946 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1947          if (allocation_now != current_allocation)
1948              fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n",
1949                current_allocation - allocation_now);
1950 
1951          if (current_allocation != 0)
1952          {
1953              memory_infop pinfo = pinformation;
1954 
1955              fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
1956                 current_allocation);
1957 
1958              while (pinfo != NULL)
1959              {
1960                 fprintf(STDERR, " %lu bytes at %p\n",
1961                    (unsigned long)pinfo->size, pinfo->pointer);
1962                 pinfo = pinfo->next;
1963              }
1964           }
1965 #endif
1966        }
1967 #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG
1968        fprintf(STDERR, " Current memory allocation: %10d bytes\n",
1969           current_allocation);
1970        fprintf(STDERR, " Maximum memory allocation: %10d bytes\n",
1971           maximum_allocation);
1972        fprintf(STDERR, " Total   memory allocation: %10d bytes\n",
1973           total_allocation);
1974        fprintf(STDERR, "     Number of allocations: %10d\n",
1975             num_allocations);
1976 #endif
1977    }
1978 
1979 #ifdef PNGTEST_TIMING
1980    t_stop = (float)clock();
1981    t_misc += (t_stop - t_start);
1982    t_start = t_stop;
1983    fprintf(STDERR, " CPU time used = %.3f seconds",
1984       (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC);
1985    fprintf(STDERR, " (decoding %.3f,\n",
1986       t_decode/(float)CLOCKS_PER_SEC);
1987    fprintf(STDERR, "        encoding %.3f ,",
1988       t_encode/(float)CLOCKS_PER_SEC);
1989    fprintf(STDERR, " other %.3f seconds)\n\n",
1990       t_misc/(float)CLOCKS_PER_SEC);
1991 #endif
1992 
1993    if (ierror == 0)
1994       fprintf(STDERR, " libpng passes test\n");
1995 
1996    else
1997       fprintf(STDERR, " libpng FAILS test\n");
1998 
1999    dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
2000    fprintf(STDERR, " Default limits:\n");
2001    fprintf(STDERR, "  width_max  = %lu\n",
2002       (unsigned long) png_get_user_width_max(dummy_ptr));
2003    fprintf(STDERR, "  height_max = %lu\n",
2004       (unsigned long) png_get_user_height_max(dummy_ptr));
2005    if (png_get_chunk_cache_max(dummy_ptr) == 0)
2006       fprintf(STDERR, "  cache_max  = unlimited\n");
2007    else
2008       fprintf(STDERR, "  cache_max  = %lu\n",
2009          (unsigned long) png_get_chunk_cache_max(dummy_ptr));
2010    if (png_get_chunk_malloc_max(dummy_ptr) == 0)
2011       fprintf(STDERR, "  malloc_max = unlimited\n");
2012    else
2013       fprintf(STDERR, "  malloc_max = %lu\n",
2014          (unsigned long) png_get_chunk_malloc_max(dummy_ptr));
2015    png_destroy_read_struct(&dummy_ptr, NULL, NULL);
2016 
2017    return (int)(ierror != 0);
2018 }
2019 #else
2020 int
main(void)2021 main(void)
2022 {
2023    fprintf(STDERR,
2024       " test ignored because libpng was not built with read support\n");
2025    /* And skip this test */
2026    return PNG_LIBPNG_VER < 10600 ? 0 : 77;
2027 }
2028 #endif
2029 
2030 /* Generate a compiler error if there is an old png.h in the search path. */
2031 typedef png_libpng_version_1_6_18 Your_png_h_is_not_version_1_6_18;
2032