• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* pngcp.c
2  *
3  * Copyright (c) 2016 John Cunningham Bowler
4  *
5  * Last changed in libpng 1.6.24 [August 4, 2016]
6  *
7  * This code is released under the libpng license.
8  * For conditions of distribution and use, see the disclaimer
9  * and license in png.h
10  *
11  * This is an example of copying a PNG without changes using the png_read_png
12  * and png_write_png interfaces.  A considerable number of options are provided
13  * to manipulate the compression of the PNG data and other compressed chunks.
14  *
15  * For a more extensive example that uses the transforms see
16  * contrib/libtests/pngimage.c in the libpng distribution.
17  */
18 #include "pnglibconf.h" /* To find how libpng was configured. */
19 
20 #ifdef PNG_PNGCP_TIMING_SUPPORTED
21    /* WARNING:
22     *
23     * This test is here to allow POSIX.1b extensions to be used if enabled in
24     * the compile; specifically the code requires_POSIX_C_SOURCE support of
25     * 199309L or later to enable clock_gettime use.
26     *
27     * IF this causes problems THEN compile with a strict ANSI C compiler and let
28     * this code turn on the POSIX features that it minimally requires.
29     *
30     * IF this does not work there is probably a bug in your ANSI C compiler or
31     * your POSIX implementation.
32     */
33 #  define _POSIX_C_SOURCE 199309L
34 #else /* No timing support required */
35 #  define _POSIX_SOURCE 1
36 #endif
37 
38 #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H)
39 #  include <config.h>
40 #endif
41 
42 #include <stdio.h>
43 
44 /* Define the following to use this test against your installed libpng, rather
45  * than the one being built here:
46  */
47 #ifdef PNG_FREESTANDING_TESTS
48 #  include <png.h>
49 #else
50 #  include "../../png.h"
51 #endif
52 
53 #if PNG_LIBPNG_VER < 10700
54    /* READ_PNG and WRITE_PNG were not defined, so: */
55 #  ifdef PNG_INFO_IMAGE_SUPPORTED
56 #     ifdef PNG_SEQUENTIAL_READ_SUPPORTED
57 #        define PNG_READ_PNG_SUPPORTED
58 #     endif /* SEQUENTIAL_READ */
59 #     ifdef PNG_WRITE_SUPPORTED
60 #        define PNG_WRITE_PNG_SUPPORTED
61 #     endif /* WRITE */
62 #  endif /* INFO_IMAGE */
63 #endif /* pre 1.7.0 */
64 
65 #if (defined(PNG_READ_PNG_SUPPORTED)) && (defined(PNG_WRITE_PNG_SUPPORTED))
66 #include <stdarg.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <errno.h>
70 #include <limits.h>
71 #include <assert.h>
72 
73 #include <unistd.h>
74 #include <sys/stat.h>
75 
76 #include <zlib.h>
77 
78 #ifndef PNG_SETJMP_SUPPORTED
79 #  include <setjmp.h> /* because png.h did *not* include this */
80 #endif
81 
82 #ifdef __cplusplus
83 #  define voidcast(type, value) static_cast<type>(value)
84 #else
85 #  define voidcast(type, value) (value)
86 #endif /* __cplusplus */
87 
88 #ifdef __GNUC__
89    /* Many versions of GCC erroneously report that local variables unmodified
90     * within the scope of a setjmp may be clobbered.  This hacks round the
91     * problem (sometimes) without harming other compilers.
92     */
93 #  define gv volatile
94 #else
95 #  define gv
96 #endif
97 
98 /* 'CLOCK_PROCESS_CPUTIME_ID' is one of the clock timers for clock_gettime.  It
99  * need not be supported even when clock_gettime is available.  It returns the
100  * 'CPU' time the process has consumed.  'CPU' time is assumed to include time
101  * when the CPU is actually blocked by a pending cache fill but not time
102  * waiting for page faults.  The attempt is to get a measure of the actual time
103  * the implementation takes to read a PNG ignoring the potentially very large IO
104  * overhead.
105  */
106 #ifdef PNG_PNGCP_TIMING_SUPPORTED
107 #  include <time.h>   /* clock_gettime and associated definitions */
108 #  ifndef CLOCK_PROCESS_CPUTIME_ID
109       /* Prevent inclusion of the spurious code: */
110 #     undef PNG_PNGCP_TIMING_SUPPORTED
111 #  endif
112 #endif /* PNGCP_TIMING */
113 
114 /* So if the timing feature has been activated: */
115 
116 /* This structure is used to control the test of a single file. */
117 typedef enum
118 {
119    VERBOSE,        /* switches on all messages */
120    INFORMATION,
121    WARNINGS,       /* switches on warnings */
122    LIBPNG_WARNING,
123    APP_WARNING,
124    ERRORS,         /* just errors */
125    APP_FAIL,       /* continuable error - no need to longjmp */
126    LIBPNG_ERROR,   /* this and higher cause a longjmp */
127    LIBPNG_BUG,     /* erroneous behavior in libpng */
128    APP_ERROR,      /* such as out-of-memory in a callback */
129    QUIET,          /* no normal messages */
130    USER_ERROR,     /* such as file-not-found */
131    INTERNAL_ERROR
132 } error_level;
133 #define LEVEL_MASK      0xf   /* where the level is in 'options' */
134 
135 #define STRICT          0x010 /* Fail on warnings as well as errors */
136 #define LOG             0x020 /* Log pass/fail to stdout */
137 #define CONTINUE        0x040 /* Continue on APP_FAIL errors */
138 #define SIZES           0x080 /* Report input and output sizes */
139 #define SEARCH          0x100 /* Search IDAT compression options */
140 #define NOWRITE         0x200 /* Do not write an output file */
141 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
142 #  define IGNORE_INDEX  0x400 /* Ignore out of range palette indices (BAD!) */
143 #  ifdef PNG_GET_PALETTE_MAX_SUPPORTED
144 #     define FIX_INDEX  0x800 /* 'Fix' out of range palette indices (OK) */
145 #  endif /* GET_PALETTE_MAX */
146 #endif /* CHECK_FOR_INVALID_INDEX */
147 #define OPTION     0x80000000 /* Used for handling options */
148 #define LIST       0x80000001 /* Used for handling options */
149 
150 /* Result masks apply to the result bits in the 'results' field below; these
151  * bits are simple 1U<<error_level.  A pass requires either nothing worse than
152  * warnings (--relaxes) or nothing worse than information (--strict)
153  */
154 #define RESULT_STRICT(r)   (((r) & ~((1U<<WARNINGS)-1)) == 0)
155 #define RESULT_RELAXED(r)  (((r) & ~((1U<<ERRORS)-1)) == 0)
156 
157 /* OPTION DEFINITIONS */
158 static const char range_lo[] = "low";
159 static const char range_hi[] = "high";
160 static const char all[] = "all";
161 #define RANGE(lo,hi) { range_lo, lo }, { range_hi, hi }
162 typedef struct value_list
163 {
164    const char *name;  /* the command line name of the value */
165    int         value; /* the actual value to use */
166 }  value_list;
167 
168 static const value_list
169 #ifdef PNG_SW_COMPRESS_png_level
170 vl_compression[] =
171 {
172    /* Overall compression control.  The order controls the search order for
173     * 'all'.  Since the search is for the smallest the order used is low memory
174     * then high speed.
175     */
176    { "low-memory",      PNG_COMPRESSION_LOW_MEMORY },
177    { "high-speed",      PNG_COMPRESSION_HIGH_SPEED },
178    { "high-read-speed", PNG_COMPRESSION_HIGH_READ_SPEED },
179    { "low",             PNG_COMPRESSION_LOW },
180    { "medium",          PNG_COMPRESSION_MEDIUM },
181    { "old",             PNG_COMPRESSION_COMPAT },
182    { "high",            PNG_COMPRESSION_HIGH },
183    { all, 0 }
184 },
185 #endif /* SW_COMPRESS_png_level */
186 
187 #if defined(PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED) ||\
188     defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED)
189 vl_strategy[] =
190 {
191    /* This controls the order of search. */
192    { "huffman", Z_HUFFMAN_ONLY },
193    { "RLE", Z_RLE },
194    { "fixed", Z_FIXED }, /* the remainder do window searchs */
195    { "filtered", Z_FILTERED },
196    { "default", Z_DEFAULT_STRATEGY },
197    { all, 0 }
198 },
199 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
200 vl_windowBits_text[] =
201 {
202    { "default", MAX_WBITS/*from zlib*/ },
203    { "minimum", 8 },
204    RANGE(8, MAX_WBITS/*from zlib*/),
205    { all, 0 }
206 },
207 #endif /* text compression */
208 vl_level[] =
209 {
210    { "default", Z_DEFAULT_COMPRESSION /* this is -1 */ },
211    { "none", Z_NO_COMPRESSION },
212    { "speed", Z_BEST_SPEED },
213    { "best", Z_BEST_COMPRESSION },
214    { "0", Z_NO_COMPRESSION },
215    RANGE(1, 9), /* this deliberately excludes '0' */
216    { all, 0 }
217 },
218 vl_memLevel[] =
219 {
220    { "max", MAX_MEM_LEVEL }, /* zlib maximum */
221    { "1", 1 }, /* zlib minimum */
222    { "default", 8 }, /* zlib default */
223    { "2", 2 },
224    { "3", 3 },
225    { "4", 4 },
226    { "5", 5 }, /* for explicit testing */
227    RANGE(6, MAX_MEM_LEVEL/*zlib*/), /* exclude 5 and below: zlib bugs */
228    { all, 0 }
229 },
230 #endif /* WRITE_CUSTOMIZE_*COMPRESSION */
231 #ifdef PNG_WRITE_FILTER_SUPPORTED
232 vl_filter[] =
233 {
234    { all,      PNG_ALL_FILTERS   },
235    { "off",    PNG_NO_FILTERS    },
236    { "none",   PNG_FILTER_NONE   },
237    { "sub",    PNG_FILTER_SUB    },
238    { "up",     PNG_FILTER_UP     },
239    { "avg",    PNG_FILTER_AVG    },
240    { "paeth",  PNG_FILTER_PAETH  }
241 },
242 #endif /* WRITE_FILTER */
243 #ifdef PNG_PNGCP_TIMING_SUPPORTED
244 #  define PNGCP_TIME_READ  1
245 #  define PNGCP_TIME_WRITE 2
246 vl_time[] =
247 {
248    { "both",  PNGCP_TIME_READ+PNGCP_TIME_WRITE },
249    { "off",   0 },
250    { "read",  PNGCP_TIME_READ },
251    { "write", PNGCP_TIME_WRITE }
252 },
253 #endif /* PNGCP_TIMING */
254 vl_IDAT_size[] = /* for png_set_IDAT_size */
255 {
256    { "default", 0x7FFFFFFF },
257    { "minimal", 1 },
258    RANGE(1, 0x7FFFFFFF)
259 },
260 #ifndef PNG_SW_IDAT_size
261    /* Pre 1.7 API: */
262 #  define png_set_IDAT_size(p,v) png_set_compression_buffer_size(p, v)
263 #endif /* !SW_IDAT_size */
264 #define SL 8 /* stack limit in display, below */
265 vl_log_depth[] = { { "on", 1 }, { "off", 0 }, RANGE(0, SL) },
266 vl_on_off[] = { { "on", 1 }, { "off", 0 } };
267 
268 #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
269 static value_list
270 vl_windowBits_IDAT[] =
271 {
272    { "default", MAX_WBITS },
273    { "small", 9 },
274    RANGE(8, MAX_WBITS), /* modified by set_windowBits_hi */
275    { all, 0 }
276 };
277 #endif /* IDAT compression */
278 
279 typedef struct option
280 {
281    const char       *name;         /* name of the option */
282    png_uint_32       opt;          /* an option, or OPTION or LIST */
283    png_byte          search;       /* Search on --search */
284    png_byte          value_count;  /* length of the list of values: */
285    const value_list *values;       /* values for OPTION or LIST */
286 }  option;
287 
288 static const option options[] =
289 {
290    /* struct display options, these are set when the command line is read */
291 #  define S(n,v) { #n, v, 0, 2, vl_on_off },
292    S(verbose,  VERBOSE)
293    S(warnings, WARNINGS)
294    S(errors,   ERRORS)
295    S(quiet,    QUIET)
296    S(strict,   STRICT)
297    S(log,      LOG)
298    S(continue, CONTINUE)
299    S(sizes,    SIZES)
300    S(search,   SEARCH)
301    S(nowrite,  NOWRITE)
302 #  ifdef IGNORE_INDEX
303       S(ignore-palette-index, IGNORE_INDEX)
304 #  endif /* IGNORE_INDEX */
305 #  ifdef FIX_INDEX
306       S(fix-palette-index, FIX_INDEX)
307 #  endif /* FIX_INDEX */
308 #  undef S
309 
310    /* OPTION settings, these and LIST settings are read on demand */
311 #  define VLNAME(name) vl_ ## name
312 #  define VLSIZE(name) voidcast(png_byte,\
313                            (sizeof VLNAME(name))/(sizeof VLNAME(name)[0]))
314 #  define VL(oname, name, type, search)\
315    { oname, type, search, VLSIZE(name), VLNAME(name) },
316 #  define VLO(oname, name, search) VL(oname, name, OPTION, search)
317 
318 #  ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
319 #     define VLCIDAT(name) VLO(#name, name, 1/*search*/)
320 #     ifdef PNG_SW_COMPRESS_level
321 #        define VLCiCCP(name) VLO("ICC-profile-" #name, name, 0/*search*/)
322 #     else
323 #        define VLCiCCP(name)
324 #     endif
325 #  else
326 #     define VLCIDAT(name)
327 #     define VLCiCCP(name)
328 #  endif /* WRITE_CUSTOMIZE_COMPRESSION */
329 
330 #  ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
331 #     define VLCzTXt(name) VLO("text-" #name, name, 0/*search*/)
332 #  else
333 #     define VLCzTXt(name)
334 #  endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
335 
336 #  define VLC(name) VLCIDAT(name) VLCiCCP(name) VLCzTXt(name)
337 
338 #  ifdef PNG_SW_COMPRESS_png_level
339       /* The libpng compression level isn't searched beause it justs sets the
340        * other things that are searched!
341        */
342       VLO("compression", compression, 0)
343       VLO("text-compression", compression, 0)
344       VLO("ICC-profile-compression", compression, 0)
345 #  endif /* SW_COMPRESS_png_level */
346    VLC(strategy)
347    VLO("windowBits", windowBits_IDAT, 1)
348 #  ifdef PNG_SW_COMPRESS_windowBits
349       VLO("ICC-profile-windowBits", windowBits_text/*sic*/, 0)
350 #  endif
351    VLO("text-windowBits", windowBits_text, 0)
352    VLC(level)
353    VLC(memLevel)
354    VLO("IDAT-size", IDAT_size, 0)
355    VLO("log-depth", log_depth, 0)
356 
357 #  undef VLO
358 
359    /* LIST settings */
360 #  define VLL(name, search) VL(#name, name, LIST, search)
361 #ifdef PNG_WRITE_FILTER_SUPPORTED
362    VLL(filter, 0)
363 #endif /* WRITE_FILTER */
364 #ifdef PNG_PNGCP_TIMING_SUPPORTED
365    VLL(time, 0)
366 #endif /* PNGCP_TIMING */
367 #  undef VLL
368 #  undef VL
369 };
370 
371 #ifdef __cplusplus
372    static const size_t option_count((sizeof options)/(sizeof options[0]));
373 #else /* !__cplusplus */
374 #  define option_count ((sizeof options)/(sizeof options[0]))
375 #endif /* !__cplusplus */
376 
377 static const char *
cts(int ct)378 cts(int ct)
379 {
380    switch (ct)
381    {
382       case PNG_COLOR_TYPE_PALETTE:     return "P";
383       case PNG_COLOR_TYPE_GRAY:        return "G";
384       case PNG_COLOR_TYPE_GRAY_ALPHA:  return "GA";
385       case PNG_COLOR_TYPE_RGB:         return "RGB";
386       case PNG_COLOR_TYPE_RGB_ALPHA:   return "RGBA";
387       default:                         return "INVALID";
388    }
389 }
390 
391 struct display
392 {
393    jmp_buf          error_return;      /* Where to go to on error */
394    unsigned int     errset;            /* error_return is set */
395 
396    const char      *operation;         /* What is happening */
397    const char      *filename;          /* The name of the original file */
398    const char      *output_file;       /* The name of the output file */
399 
400    /* Used on both read and write: */
401    FILE            *fp;
402 
403    /* Used on a read, both the original read and when validating a written
404     * image.
405     */
406    png_alloc_size_t read_size;
407    png_structp      read_pp;
408    png_infop        ip;
409 #  if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
410       png_textp     text_ptr; /* stash of text chunks */
411       int           num_text;
412       int           text_stashed;
413 #  endif /* pre 1.7 */
414 
415 #  ifdef PNG_PNGCP_TIMING_SUPPORTED
416       struct timespec   read_time;
417       struct timespec   read_time_total;
418       struct timespec   write_time;
419       struct timespec   write_time_total;
420 #  endif /* PNGCP_TIMING */
421 
422    /* Used to write a new image (the original info_ptr is used) */
423 #  define MAX_SIZE ((png_alloc_size_t)(-1))
424    png_alloc_size_t write_size;
425    png_alloc_size_t best_size;
426    png_structp      write_pp;
427 
428    /* Base file information */
429    png_alloc_size_t size;
430    png_uint_32      w;
431    png_uint_32      h;
432    int              bpp;
433    png_byte         ct;
434    int              no_warnings;       /* Do not output libpng warnings */
435    int              min_windowBits;    /* The windowBits range is 8..8 */
436 
437    /* Options handling */
438    png_uint_32      results;             /* A mask of errors seen */
439    png_uint_32      options;             /* See display_log below */
440    png_byte         entry[option_count]; /* The selected entry+1 of an option
441                                           * that appears on the command line, or
442                                           * 0 if it was not given. */
443    int              value[option_count]; /* Corresponding value */
444 
445    /* Compression exhaustive testing */
446    /* Temporary variables used only while testing a single collection of
447     * settings:
448     */
449    unsigned int     csp;               /* next stack entry to use */
450    unsigned int     nsp;               /* highest active entry+1 found so far */
451 
452    /* Values used while iterating through all the combinations of settings for a
453     * single file:
454     */
455    unsigned int     tsp;               /* nsp from the last run; this is the
456                                         * index+1 of the highest active entry on
457                                         * this run; this entry will be advanced.
458                                         */
459    int              opt_string_start;  /* Position in buffer for the first
460                                         * searched option; non-zero if earlier
461                                         * options were set on the command line.
462                                         */
463    struct stack
464    {
465       png_alloc_size_t best_size;      /* Best so far for this option */
466       png_alloc_size_t lo_size;
467       png_alloc_size_t hi_size;
468       int              lo, hi;         /* For binary chop of a range */
469       int              best_val;       /* Best value found so far */
470       int              opt_string_end; /* End of the option string in 'curr' */
471       png_byte         opt;            /* The option being tested */
472       png_byte         entry;          /* The next value entry to be tested */
473       png_byte         end;            /* This is the last entry */
474    }                stack[SL];         /* Stack of entries being tested */
475    char             curr[32*SL];       /* current options being tested */
476    char             best[32*SL];       /* best options */
477 
478    char             namebuf[FILENAME_MAX]; /* output file name */
479 };
480 
481 static void
display_init(struct display * dp)482 display_init(struct display *dp)
483    /* Call this only once right at the start to initialize the control
484     * structure, the (struct buffer) lists are maintained across calls - the
485     * memory is not freed.
486     */
487 {
488    memset(dp, 0, sizeof *dp);
489    dp->operation = "internal error";
490    dp->filename = "command line";
491    dp->output_file = "no output file";
492    dp->options = WARNINGS; /* default to !verbose, !quiet */
493    dp->fp = NULL;
494    dp->read_pp = NULL;
495    dp->ip = NULL;
496    dp->write_pp = NULL;
497    dp->min_windowBits = -1; /* this is an OPTIND, so -1 won't match anything */
498 #  if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
499       dp->text_ptr = NULL;
500       dp->num_text = 0;
501       dp->text_stashed = 0;
502 #  endif /* pre 1.7 */
503 }
504 
505 static void
display_clean_read(struct display * dp)506 display_clean_read(struct display *dp)
507 {
508    if (dp->read_pp != NULL)
509       png_destroy_read_struct(&dp->read_pp, NULL, NULL);
510 
511    if (dp->fp != NULL)
512    {
513       FILE *fp = dp->fp;
514       dp->fp = NULL;
515       (void)fclose(fp);
516    }
517 }
518 
519 static void
display_clean_write(struct display * dp)520 display_clean_write(struct display *dp)
521 {
522    if (dp->fp != NULL)
523    {
524       FILE *fp = dp->fp;
525       dp->fp = NULL;
526       (void)fclose(fp);
527    }
528 
529    if (dp->write_pp != NULL)
530       png_destroy_write_struct(&dp->write_pp, dp->tsp > 0 ? NULL : &dp->ip);
531 }
532 
533 static void
display_clean(struct display * dp)534 display_clean(struct display *dp)
535 {
536    display_clean_read(dp);
537    display_clean_write(dp);
538    dp->output_file = NULL;
539 
540 #  if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
541       /* This is actually created and used by the write code, but only
542        * once; it has to be retained for subsequent writes of the same file.
543        */
544       if (dp->text_stashed)
545       {
546          dp->text_stashed = 0;
547          dp->num_text = 0;
548          free(dp->text_ptr);
549          dp->text_ptr = NULL;
550       }
551 #  endif /* pre 1.7 */
552 
553    /* leave the filename for error detection */
554    dp->results = 0; /* reset for next time */
555 }
556 
557 static void
display_destroy(struct display * dp)558 display_destroy(struct display *dp)
559 {
560    /* Release any memory held in the display. */
561    display_clean(dp);
562 }
563 
564 static struct display *
get_dp(png_structp pp)565 get_dp(png_structp pp)
566    /* The display pointer is always stored in the png_struct error pointer */
567 {
568    struct display *dp = (struct display*)png_get_error_ptr(pp);
569 
570    if (dp == NULL)
571    {
572       fprintf(stderr, "pngcp: internal error (no display)\n");
573       exit(99); /* prevents a crash */
574    }
575 
576    return dp;
577 }
578 
579 /* error handling */
580 #ifdef __GNUC__
581 #  define VGATTR __attribute__((__format__ (__printf__,3,4)))
582    /* Required to quiet GNUC warnings when the compiler sees a stdarg function
583     * that calls one of the stdio v APIs.
584     */
585 #else
586 #  define VGATTR
587 #endif
588 static void VGATTR
display_log(struct display * dp,error_level level,const char * fmt,...)589 display_log(struct display *dp, error_level level, const char *fmt, ...)
590    /* 'level' is as above, fmt is a stdio style format string.  This routine
591     * does not return if level is above LIBPNG_WARNING
592     */
593 {
594    dp->results |= 1U << level;
595 
596    if (level > (error_level)(dp->options & LEVEL_MASK))
597    {
598       const char *lp;
599       va_list ap;
600 
601       switch (level)
602       {
603          case INFORMATION:    lp = "information"; break;
604          case LIBPNG_WARNING: lp = "warning(libpng)"; break;
605          case APP_WARNING:    lp = "warning(pngcp)"; break;
606          case APP_FAIL:       lp = "error(continuable)"; break;
607          case LIBPNG_ERROR:   lp = "error(libpng)"; break;
608          case LIBPNG_BUG:     lp = "bug(libpng)"; break;
609          case APP_ERROR:      lp = "error(pngcp)"; break;
610          case USER_ERROR:     lp = "error(user)"; break;
611 
612          case INTERNAL_ERROR: /* anything unexpected is an internal error: */
613          case VERBOSE: case WARNINGS: case ERRORS: case QUIET:
614          default:             lp = "bug(pngcp)"; break;
615       }
616 
617       fprintf(stderr, "%s: %s: %s",
618          dp->filename != NULL ? dp->filename : "<stdin>", lp, dp->operation);
619 
620       fprintf(stderr, ": ");
621 
622       va_start(ap, fmt);
623       vfprintf(stderr, fmt, ap);
624       va_end(ap);
625 
626       fputc('\n', stderr);
627    }
628    /* else do not output any message */
629 
630    /* Errors cause this routine to exit to the fail code */
631    if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
632    {
633       if (dp->errset)
634          longjmp(dp->error_return, level);
635 
636       else
637          exit(99);
638    }
639 }
640 
641 #if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
642 static void
text_stash(struct display * dp)643 text_stash(struct display *dp)
644 {
645    /* libpng 1.6 and earlier fixed a bug whereby text chunks were written
646     * multiple times by png_write_png; the issue was that png_write_png passed
647     * the same png_info to both png_write_info and png_write_end.  Rather than
648     * fixing it by recording the information in the png_struct, or by recording
649     * where to write the chunks, the fix made was to change the 'compression'
650     * field of the chunk to invalid values, rendering the png_info somewhat
651     * useless.
652     *
653     * The only fix for this given that we use the png_info more than once is to
654     * make a copy of the text chunks and png_set_text it each time.  This adds a
655     * text chunks, so they get replicated, but only the new set gets written
656     * each time.  This uses memory like crazy but there is no way to delete the
657     * useless chunks from the png_info.
658     *
659     * To make this slightly more efficient only the top level structure is
660     * copied; since the old strings are actually preserved (in 1.6 and earlier)
661     * this happens to work.
662     */
663    png_textp chunks = NULL;
664 
665    dp->num_text = png_get_text(dp->write_pp, dp->ip, &chunks, NULL);
666 
667    if (dp->num_text > 0)
668    {
669       dp->text_ptr = voidcast(png_textp, malloc(dp->num_text * sizeof *chunks));
670 
671       if (dp->text_ptr == NULL)
672          display_log(dp, APP_ERROR, "text chunks: stash malloc failed");
673 
674       else
675          memcpy(dp->text_ptr, chunks, dp->num_text * sizeof *chunks);
676    }
677 
678    dp->text_stashed = 1; /* regardless of whether there are chunks or not */
679 }
680 
681 #define text_stash(dp) if (!dp->text_stashed) text_stash(dp)
682 
683 static void
text_restore(struct display * dp)684 text_restore(struct display *dp)
685 {
686    /* libpng makes a copy, so this is fine: */
687    if (dp->text_ptr != NULL)
688       png_set_text(dp->write_pp, dp->ip, dp->text_ptr, dp->num_text);
689 }
690 
691 #define text_restore(dp) if (dp->text_stashed) text_restore(dp)
692 
693 #else
694 #define text_stash(dp) ((void)0)
695 #define text_restore(dp) ((void)0)
696 #endif /* pre 1.7 */
697 
698 /* OPTIONS:
699  *
700  * The command handles options of the forms:
701  *
702  *    --option
703  *       Turn an option on (Option)
704  *    --no-option
705  *       Turn an option off (Option)
706  *    --option=value
707  *       Set an option to a value (Value)
708  *    --option=val1,val2,val3
709  *       Set an option to a bitmask constructed from the values (List)
710  */
711 static png_byte
option_index(struct display * dp,const char * opt,size_t len)712 option_index(struct display *dp, const char *opt, size_t len)
713    /* Return the index (in options[]) of the given option, outputs an error if
714     * it does not exist.  Takes the name of the option and a length (number of
715     * characters in the name).
716     */
717 {
718    png_byte j;
719 
720    for (j=0; j<option_count; ++j)
721       if (strncmp(options[j].name, opt, len) == 0 && options[j].name[len] == 0)
722          return j;
723 
724    /* If the setjmp buffer is set the code is asking for an option index; this
725     * is bad.  Otherwise this is the command line option parsing.
726     */
727    display_log(dp, dp->errset ? INTERNAL_ERROR : USER_ERROR,
728          "%.*s: unknown option", (int)/*SAFE*/len, opt);
729    abort(); /* NOT REACHED */
730 }
731 
732 /* This works for an option name (no quotes): */
733 #define OPTIND(dp, name) option_index(dp, #name, (sizeof #name)-1)
734 
735 static int
get_option(struct display * dp,const char * opt,int * value)736 get_option(struct display *dp, const char *opt, int *value)
737 {
738    const png_byte i = option_index(dp, opt, strlen(opt));
739 
740    if (dp->entry[i]) /* option was set on command line */
741    {
742       *value = dp->value[i];
743       return 1;
744    }
745 
746    else
747       return 0;
748 }
749 
750 static int
set_opt_string_(struct display * dp,unsigned int sp,png_byte opt,const char * entry_name)751 set_opt_string_(struct display *dp, unsigned int sp, png_byte opt,
752       const char *entry_name)
753    /* Add the appropriate option string to dp->curr. */
754 {
755    int offset, add;
756 
757    if (sp > 0)
758       offset = dp->stack[sp-1].opt_string_end;
759 
760    else
761       offset = dp->opt_string_start;
762 
763    if (entry_name == range_lo)
764       add = sprintf(dp->curr+offset, " --%s=%d", options[opt].name,
765             dp->value[opt]);
766 
767    else
768       add = sprintf(dp->curr+offset, " --%s=%s", options[opt].name, entry_name);
769 
770    if (add < 0)
771       display_log(dp, INTERNAL_ERROR, "sprintf failed");
772 
773    assert(offset+add < (int)/*SAFE*/sizeof dp->curr);
774    return offset+add;
775 }
776 
777 static void
set_opt_string(struct display * dp,unsigned int sp)778 set_opt_string(struct display *dp, unsigned int sp)
779    /* Add the appropriate option string to dp->curr. */
780 {
781    dp->stack[sp].opt_string_end = set_opt_string_(dp, sp, dp->stack[sp].opt,
782       options[dp->stack[sp].opt].values[dp->stack[sp].entry].name);
783 }
784 
785 static void
record_opt(struct display * dp,png_byte opt,const char * entry_name)786 record_opt(struct display *dp, png_byte opt, const char *entry_name)
787    /* Record this option in dp->curr; called for an option not being searched,
788     * the caller passes in the name of the value, or range_lo to use the
789     * numerical value.
790     */
791 {
792    const unsigned int sp = dp->csp; /* stack entry of next searched option */
793 
794    if (sp >= dp->tsp)
795    {
796       /* At top of stack; add the opt string for this entry to the previous
797        * searched entry or the start of the dp->curr buffer if there is nothing
798        * on the stack yet (sp == 0).
799        */
800       const int offset = set_opt_string_(dp, sp, opt, entry_name);
801 
802       if (sp > 0)
803          dp->stack[sp-1].opt_string_end = offset;
804 
805       else
806          dp->opt_string_start = offset;
807    }
808 
809    /* else do nothing: option already recorded */
810 }
811 
812 static int
opt_list_end(struct display * dp,png_byte opt,png_byte entry)813 opt_list_end(struct display *dp, png_byte opt, png_byte entry)
814 {
815    if (options[opt].values[entry].name == range_lo)
816       return entry+1U >= options[opt].value_count /* missing range_hi */ ||
817          options[opt].values[entry+1U].name != range_hi /* likewise */ ||
818          options[opt].values[entry+1U].value <= dp->value[opt] /* range end */;
819 
820    else
821       return entry+1U >= options[opt].value_count /* missing 'all' */ ||
822          options[opt].values[entry+1U].name == all /* last entry */;
823 }
824 
825 static void
push_opt(struct display * dp,unsigned int sp,png_byte opt,int search)826 push_opt(struct display *dp, unsigned int sp, png_byte opt, int search)
827    /* Push a new option onto the stack, initializing the new stack entry
828     * appropriately; this does all the work of next_opt (setting end/nsp) for
829     * the first entry in the list.
830     */
831 {
832    png_byte entry;
833    const char *entry_name;
834 
835    assert(sp == dp->tsp && sp < SL);
836 
837    /* The starting entry is entry 0 unless there is a range in which case it is
838     * the entry corresponding to range_lo:
839     */
840    entry = options[opt].value_count;
841    assert(entry > 0U);
842 
843    do
844    {
845       entry_name = options[opt].values[--entry].name;
846       if (entry_name == range_lo)
847          break;
848    }
849    while (entry > 0U);
850 
851    dp->tsp = sp+1U;
852    dp->stack[sp].best_size =
853       dp->stack[sp].lo_size =
854       dp->stack[sp].hi_size = MAX_SIZE;
855 
856    if (search && entry_name == range_lo) /* search this range */
857    {
858       dp->stack[sp].lo = options[opt].values[entry].value;
859       /* check for a mal-formed RANGE above: */
860       assert(entry+1 < options[opt].value_count &&
861              options[opt].values[entry+1].name == range_hi);
862       dp->stack[sp].hi = options[opt].values[entry+1].value;
863    }
864 
865    else
866    {
867       /* next_opt will just iterate over the range. */
868       dp->stack[sp].lo = INT_MAX;
869       dp->stack[sp].hi = INT_MIN; /* Prevent range chop */
870    }
871 
872    dp->stack[sp].opt = opt;
873    dp->stack[sp].entry = entry;
874    dp->stack[sp].best_val = dp->value[opt] = options[opt].values[entry].value;
875 
876    set_opt_string(dp, sp);
877 
878    /* This works for the search case too; if the range has only one entry 'end'
879     * will be marked here.
880     */
881    if (opt_list_end(dp, opt, entry))
882    {
883       dp->stack[sp].end = 1;
884       /* Skip the warning if pngcp did this itself.  See the code in
885        * set_windowBits_hi.
886        */
887       if (opt != dp->min_windowBits)
888          display_log(dp, APP_WARNING, "%s: only testing one value",
889                options[opt].name);
890    }
891 
892    else
893    {
894       dp->stack[sp].end = 0;
895       dp->nsp = dp->tsp;
896    }
897 
898    /* Do a lazy cache of the text chunks for libpng 1.6 and earlier; this is
899     * because they can only be written once(!) so if we are going to re-use the
900     * png_info we need a copy.
901     */
902    text_stash(dp);
903 }
904 
905 static void
next_opt(struct display * dp,unsigned int sp)906 next_opt(struct display *dp, unsigned int sp)
907    /* Return the next value for this option.  When called 'sp' is expected to be
908     * the topmost stack entry - only the topmost entry changes each time round -
909     * and there must be a valid entry to return.  next_opt will set dp->nsp to
910     * sp+1 if more entries are available, otherwise it will not change it and
911     * set dp->stack[s].end to true.
912     */
913 {
914    int search = 0;
915    png_byte entry, opt;
916    const char *entry_name;
917 
918    /* dp->stack[sp] must be the top stack entry and it must be active: */
919    assert(sp+1U == dp->tsp && !dp->stack[sp].end);
920 
921    opt = dp->stack[sp].opt;
922    entry = dp->stack[sp].entry;
923    assert(entry+1U < options[opt].value_count);
924    entry_name = options[opt].values[entry].name;
925    assert(entry_name != NULL);
926 
927    /* For ranges increment the value but don't change the entry, for all other
928     * cases move to the next entry and load its value:
929     */
930    if (entry_name == range_lo) /* a range */
931    {
932       /* A range can be iterated over or searched.  The default iteration option
933        * is indicated by hi < lo on the stack, otherwise the range being search
934        * is [lo..hi] (inclusive).
935        */
936       if (dp->stack[sp].lo > dp->stack[sp].hi)
937          dp->value[opt]++;
938 
939       else
940       {
941          /* This is the best size found for this option value: */
942          png_alloc_size_t best_size = dp->stack[sp].best_size;
943          int lo = dp->stack[sp].lo;
944          int hi = dp->stack[sp].hi;
945          int val = dp->value[opt];
946 
947          search = 1; /* end is determined here */
948          assert(best_size < MAX_SIZE);
949 
950          if (val == lo)
951          {
952             /* Finding the best for the low end of the range: */
953             dp->stack[sp].lo_size = best_size;
954             assert(hi > val);
955 
956             if (hi == val+1) /* only 2 entries */
957                dp->stack[sp].end = 1;
958 
959             val = hi;
960          }
961 
962          else if (val == hi)
963          {
964             dp->stack[sp].hi_size = best_size;
965             assert(val > lo+1); /* else 'end' set above */
966 
967             if (val == lo+2) /* only three entries to test */
968                dp->stack[sp].end = 1;
969 
970             val = (lo + val)/2;
971          }
972 
973          else
974          {
975             png_alloc_size_t lo_size = dp->stack[sp].lo_size;
976             png_alloc_size_t hi_size = dp->stack[sp].hi_size;
977 
978             /* lo and hi should have been tested. */
979             assert(lo_size < MAX_SIZE && hi_size < MAX_SIZE);
980 
981             /* These cases arise with the 'probe' handling below when there is a
982              * dip or peak in the size curve.
983              */
984             if (val < lo) /* probing a new lo */
985             {
986                /* Swap lo and val: */
987                dp->stack[sp].lo = val;
988                dp->stack[sp].lo_size = best_size;
989                val = lo;
990                best_size = lo_size;
991                lo = dp->stack[sp].lo;
992                lo_size = dp->stack[sp].lo_size;
993             }
994 
995             else if (val > hi) /* probing a new hi */
996             {
997                /* Swap hi and val: */
998                dp->stack[sp].hi = val;
999                dp->stack[sp].hi_size = best_size;
1000                val = hi;
1001                best_size = hi_size;
1002                hi = dp->stack[sp].hi;
1003                hi_size = dp->stack[sp].hi_size;
1004             }
1005 
1006             /* The following should be true or something got messed up above. */
1007             assert(lo < val && val < hi);
1008 
1009             /* If there are only four entries (lo, val, hi plus one more) just
1010              * test the remaining entry.
1011              */
1012             if (hi == lo+3)
1013             {
1014                /* Because of the 'probe' code val can either be lo+1 or hi-1; we
1015                 * need to test the other.
1016                 */
1017                val = lo + ((val == lo+1) ? 2 : 1);
1018                assert(lo < val && val < hi);
1019                dp->stack[sp].end = 1;
1020             }
1021 
1022             else
1023             {
1024                /* There are at least 2 entries still untested between lo and hi,
1025                 * i.e. hi >= lo+4.  'val' is the midpoint +/- 0.5
1026                 *
1027                 * Separate out the four easy cases when lo..val..hi are
1028                 * monotonically decreased or (more weird) increasing:
1029                 */
1030                assert(hi > lo+3);
1031 
1032                if (lo_size <= best_size && best_size <= hi_size)
1033                {
1034                   /* Select the low range; testing this first favours the low
1035                    * range over the high range when everything comes out equal.
1036                    * Because of the probing 'val' may be lo+1.  In that case end
1037                    * the search and set 'val' to lo+2.
1038                    */
1039                   if (val == lo+1)
1040                   {
1041                      ++val;
1042                      dp->stack[sp].end = 1;
1043                   }
1044 
1045                   else
1046                   {
1047                      dp->stack[sp].hi = hi = val;
1048                      dp->stack[sp].hi_size = best_size;
1049                      val = (lo + val) / 2;
1050                   }
1051                }
1052 
1053                else if (lo_size >= best_size && best_size >= hi_size)
1054                {
1055                   /* Monotonically decreasing size; this is the expected case.
1056                    * Select the high end of the range.  As above, val may be
1057                    * hi-1.
1058                    */
1059                   if (val == hi-1)
1060                   {
1061                      --val;
1062                      dp->stack[sp].end = 1;
1063                   }
1064 
1065                   else
1066                   {
1067                      dp->stack[sp].lo = lo = val;
1068                      dp->stack[sp].lo_size = best_size;
1069                      val = (val + hi) / 2;
1070                   }
1071                }
1072 
1073                /* If both those tests failed 'best_size' is either greater than
1074                 * or less than both lo_size and hi_size.  There is a peak or dip
1075                 * in the curve of sizes from lo to hi and val is on the peak or
1076                 * dip.
1077                 *
1078                 * Because the ranges being searched as so small (level is 1..9,
1079                 * windowBits 8..15, memLevel 1..9) there will only be at most
1080                 * three untested values between lo..val and val..hi, so solve
1081                 * the problem by probing down from hi or up from lo, whichever
1082                 * is the higher.
1083                 *
1084                 * This is the place where 'val' is set to outside the range
1085                 * lo..hi, described as 'probing', though maybe 'narrowing' would
1086                 * be more accurate.
1087                 */
1088                else if (lo_size <= hi_size) /* down from hi */
1089                {
1090                   dp->stack[sp].hi = val;
1091                   dp->stack[sp].hi_size = best_size;
1092                   val = --hi;
1093                }
1094 
1095                else /* up from low */
1096                {
1097                   dp->stack[sp].lo = val;
1098                   dp->stack[sp].lo_size = best_size;
1099                   val = ++lo;
1100                }
1101 
1102                /* lo and hi are still the true range limits, check for the end
1103                 * condition.
1104                 */
1105                assert(hi > lo+1);
1106                if (hi <= lo+2)
1107                   dp->stack[sp].end = 1;
1108             }
1109          }
1110 
1111          assert(val != dp->stack[sp].best_val); /* should be a new value */
1112          dp->value[opt] = val;
1113          dp->stack[sp].best_size = MAX_SIZE;
1114       }
1115    }
1116 
1117    else
1118    {
1119       /* Increment 'entry' */
1120       dp->value[opt] = options[opt].values[++entry].value;
1121       dp->stack[sp].entry = entry;
1122    }
1123 
1124    set_opt_string(dp, sp);
1125 
1126    if (!search && opt_list_end(dp, opt, entry)) /* end of list */
1127       dp->stack[sp].end = 1;
1128 
1129    else if (!dp->stack[sp].end) /* still active after all these tests */
1130       dp->nsp = dp->tsp;
1131 }
1132 
1133 static int
compare_option(const struct display * dp,unsigned int sp)1134 compare_option(const struct display *dp, unsigned int sp)
1135 {
1136    int opt = dp->stack[sp].opt;
1137 
1138    /* If the best so far is numerically less than the current value the
1139     * current set of options is invariably worse.
1140     */
1141    if (dp->stack[sp].best_val < dp->value[opt])
1142       return -1;
1143 
1144    /* Lists of options are searched out of numerical order (currently only
1145     * strategy), so only return +1 here when a range is being searched.
1146     */
1147    else if (dp->stack[sp].best_val > dp->value[opt])
1148    {
1149       if (dp->stack[sp].lo <= dp->stack[sp].hi /*searching*/)
1150          return 1;
1151 
1152       else
1153          return -1;
1154    }
1155 
1156    else
1157       return 0; /* match; current value is the best one */
1158 }
1159 
1160 static int
advance_opt(struct display * dp,png_byte opt,int search)1161 advance_opt(struct display *dp, png_byte opt, int search)
1162 {
1163    unsigned int sp = dp->csp++; /* my stack entry */
1164 
1165    assert(sp >= dp->nsp); /* nsp starts off zero */
1166 
1167    /* If the entry was active in the previous run dp->stack[sp] is already
1168     * set up and dp->tsp will be greater than sp, otherwise a new entry
1169     * needs to be created.
1170     *
1171     * dp->nsp is handled this way:
1172     *
1173     * 1) When an option is pushed onto the stack dp->nsp and dp->tsp are
1174     *    both set (by push_opt) to the next stack entry *unless* there is
1175     *    only one entry in the new list, in which case dp->stack[sp].end
1176     *    is set.
1177     *
1178     * 2) For the top stack entry next_opt is called.  The entry must be
1179     *    active (dp->stack[sp].end is not set) and either 'nsp' or 'end'
1180     *    will be updated as appropriate.
1181     *
1182     * 3) For lower stack entries nsp is set unless the stack entry is
1183     *    already at the end.  This means that when all the higher entries
1184     *    are popped this entry will be too.
1185     */
1186    if (sp >= dp->tsp)
1187    {
1188       push_opt(dp, sp, opt, search); /* This sets tsp to sp+1 */
1189       return 1; /* initialized */
1190    }
1191 
1192    else
1193    {
1194       int ret = 0; /* unchanged */
1195 
1196       /* An option that is already on the stack; update best_size and best_val
1197        * if appropriate.  On the first run there are no previous values and
1198        * dp->write_size will be MAX_SIZE, however on the first run dp->tsp
1199        * starts off as 0.
1200        */
1201       assert(dp->write_size > 0U && dp->write_size < MAX_SIZE);
1202 
1203       if (dp->stack[sp].best_size > dp->write_size ||
1204           (dp->stack[sp].best_size == dp->write_size &&
1205            compare_option(dp, sp) > 0))
1206       {
1207          dp->stack[sp].best_size = dp->write_size;
1208          dp->stack[sp].best_val = dp->value[opt];
1209       }
1210 
1211       if (sp+1U >= dp->tsp)
1212       {
1213          next_opt(dp, sp);
1214          ret = 1; /* advanced */
1215       }
1216 
1217       else if (!dp->stack[sp].end) /* Active, not at top of stack */
1218          dp->nsp = sp+1U;
1219 
1220       return ret; /* advanced || unchanged */
1221    }
1222 }
1223 
1224 static int
getallopts_(struct display * dp,const png_byte opt,int * value,int record)1225 getallopts_(struct display *dp, const png_byte opt, int *value, int record)
1226    /* Like getop but iterate over all the values if the option was set to "all".
1227     */
1228 {
1229    if (dp->entry[opt]) /* option was set on command line */
1230    {
1231       /* Simple, single value, entries don't have a stack frame and have a fixed
1232        * value (it doesn't change once set on the command line).  Otherwise the
1233        * value (entry) selected from the command line is 'all':
1234        */
1235       const char *entry_name = options[opt].values[dp->entry[opt]-1].name;
1236 
1237       if (entry_name == all)
1238          (void)advance_opt(dp, opt, 0/*do not search; iterate*/);
1239 
1240       else if (record)
1241          record_opt(dp, opt, entry_name);
1242 
1243       *value = dp->value[opt];
1244       return 1; /* set */
1245    }
1246 
1247    else
1248       return 0; /* not set */
1249 }
1250 
1251 static int
getallopts(struct display * dp,const char * opt_str,int * value)1252 getallopts(struct display *dp, const char *opt_str, int *value)
1253 {
1254    return getallopts_(dp, option_index(dp, opt_str, strlen(opt_str)), value, 0);
1255 }
1256 
1257 static int
getsearchopts(struct display * dp,const char * opt_str,int * value)1258 getsearchopts(struct display *dp, const char *opt_str, int *value)
1259    /* As above except that if the option was not set try a search */
1260 {
1261    png_byte istrat;
1262    const png_byte opt = option_index(dp, opt_str, strlen(opt_str));
1263    int record = options[opt].search;
1264    const char *entry_name;
1265 
1266    /* If it was set on the command line honour the setting, including 'all'
1267     * which will override the built in search:
1268     */
1269    if (getallopts_(dp, opt, value, record))
1270       return 1;
1271 
1272    else if (!record) /* not a search option */
1273       return 0; /* unset and not searched */
1274 
1275    /* Otherwise decide what to do here. */
1276    istrat = OPTIND(dp, strategy);
1277    entry_name = range_lo; /* record the value, not the name */
1278 
1279    if (opt == istrat) /* search all strategies */
1280       (void)advance_opt(dp, opt, 0/*iterate*/), record=0;
1281 
1282    else if (opt == OPTIND(dp, level))
1283    {
1284       /* Both RLE and HUFFMAN don't benefit from level increases */
1285       if (dp->value[istrat] == Z_RLE || dp->value[istrat] == Z_HUFFMAN_ONLY)
1286          dp->value[opt] = 1;
1287 
1288       else /* fixed, filtered or default */
1289          (void)advance_opt(dp, opt, 1/*search*/), record=0;
1290    }
1291 
1292    else if (opt == OPTIND(dp, windowBits))
1293    {
1294       /* Changing windowBits for strategies that do not search the window is
1295        * pointless.  Huffman-only does not search, RLE only searches backwards
1296        * one byte, so given that the maximum string length is 258, a windowBits
1297        * of 9 is always sufficient.
1298        */
1299       if (dp->value[istrat] == Z_HUFFMAN_ONLY)
1300          dp->value[opt] = 8;
1301 
1302       else if (dp->value[istrat] == Z_RLE)
1303          dp->value[opt] = 9;
1304 
1305       else /* fixed, filtered or default */
1306          (void)advance_opt(dp, opt, 1/*search*/), record=0;
1307    }
1308 
1309    else if (opt == OPTIND(dp, memLevel))
1310    {
1311 #     if 0
1312          (void)advance_opt(dp, opt, 0/*all*/), record=0;
1313 #     else
1314          dp->value[opt] = MAX_MEM_LEVEL;
1315 #     endif
1316    }
1317 
1318    else /* something else */
1319       assert(0=="reached");
1320 
1321    if (record)
1322       record_opt(dp, opt, entry_name);
1323 
1324    /* One of the above searched options: */
1325    *value = dp->value[opt];
1326    return 1;
1327 }
1328 
1329 static int
find_val(struct display * dp,png_byte opt,const char * str,size_t len)1330 find_val(struct display *dp, png_byte opt, const char *str, size_t len)
1331    /* Like option_index but sets (index+i) of the entry in options[opt] that
1332     * matches str[0..len-1] into dp->entry[opt] as well as returning the actual
1333     * value.
1334     */
1335 {
1336    int rlo = INT_MAX, rhi = INT_MIN;
1337    png_byte j, irange = 0;
1338 
1339    for (j=1U; j<=options[opt].value_count; ++j)
1340    {
1341       if (strncmp(options[opt].values[j-1U].name, str, len) == 0 &&
1342           options[opt].values[j-1U].name[len] == 0)
1343       {
1344          dp->entry[opt] = j;
1345          return options[opt].values[j-1U].value;
1346       }
1347       else if (options[opt].values[j-1U].name == range_lo)
1348          rlo = options[opt].values[j-1U].value, irange = j;
1349       else if (options[opt].values[j-1U].name == range_hi)
1350          rhi = options[opt].values[j-1U].value;
1351    }
1352 
1353    /* No match on the name, but there may be a range. */
1354    if (irange > 0)
1355    {
1356       char *ep = NULL;
1357       long l = strtol(str, &ep, 0);
1358 
1359       if (ep == str+len && l >= rlo && l <= rhi)
1360       {
1361          dp->entry[opt] = irange; /* range_lo */
1362          return (int)/*SAFE*/l;
1363       }
1364    }
1365 
1366    display_log(dp, dp->errset ? INTERNAL_ERROR : USER_ERROR,
1367          "%s: unknown value setting '%.*s'", options[opt].name,
1368          (int)/*SAFE*/len, str);
1369    abort(); /* NOT REACHED */
1370 }
1371 
1372 static int
opt_check(struct display * dp,const char * arg)1373 opt_check(struct display *dp, const char *arg)
1374 {
1375    assert(dp->errset == 0);
1376 
1377    if (arg != NULL && arg[0] == '-' && arg[1] == '-')
1378    {
1379       int i = 0, negate = (strncmp(arg+2, "no-", 3) == 0), val;
1380       png_byte j;
1381 
1382       if (negate)
1383          arg += 5; /* --no- */
1384 
1385       else
1386          arg += 2; /* -- */
1387 
1388       /* Find the length (expect arg\0 or arg=) */
1389       while (arg[i] != 0 && arg[i] != '=') ++i;
1390 
1391       /* So arg[0..i-1] is the argument name, this does not return if this isn't
1392        * a valid option name.
1393        */
1394       j = option_index(dp, arg, i);
1395 
1396       /* It matcheth an option; check the remainder. */
1397       if (arg[i] == 0) /* no specified value, use the default */
1398       {
1399          val = options[j].values[negate].value;
1400          dp->entry[j] = (png_byte)/*SAFE*/(negate + 1U);
1401       }
1402 
1403       else
1404       {
1405          const char *list = arg + (i+1);
1406 
1407          /* Expect a single value here unless this is a list, in which case
1408           * multiple values are combined.
1409           */
1410          if (options[j].opt != LIST)
1411          {
1412             /* find_val sets 'dp->entry[j]' to a non-zero value: */
1413             val = find_val(dp, j, list, strlen(list));
1414 
1415             if (negate)
1416             {
1417                if (options[j].opt < OPTION)
1418                   val = !val;
1419 
1420                else
1421                {
1422                   display_log(dp, USER_ERROR,
1423                         "%.*s: option=arg cannot be negated", i, arg);
1424                   abort(); /* NOT REACHED */
1425                }
1426             }
1427          }
1428 
1429          else /* multiple options separated by ',' characters */
1430          {
1431             /* --no-option negates list values from the default, which should
1432              * therefore be 'all'.  Notice that if the option list is empty in
1433              * this case nothing will be removed and therefore --no-option= is
1434              * the same as --option.
1435              */
1436             if (negate)
1437                val = options[j].values[0].value;
1438 
1439             else
1440                val = 0;
1441 
1442             while (*list != 0) /* allows option= which sets 0 */
1443             {
1444                /* A value is terminated by the end of the list or a ','
1445                 * character.
1446                 */
1447                int v, iv;
1448 
1449                iv = 0; /* an index into 'list' */
1450                while (list[++iv] != 0 && list[iv] != ',') {}
1451 
1452                v = find_val(dp, j, list, iv);
1453 
1454                if (negate)
1455                   val &= ~v;
1456 
1457                else
1458                   val |= v;
1459 
1460                list += iv;
1461                if (*list != 0)
1462                   ++list; /* skip the ',' */
1463             }
1464          }
1465       }
1466 
1467       /* 'val' is the new value, store it for use later and debugging: */
1468       dp->value[j] = val;
1469 
1470       if (options[j].opt < LEVEL_MASK)
1471       {
1472          /* The handling for error levels is to set the level. */
1473          if (val) /* Set this level */
1474             dp->options = (dp->options & ~LEVEL_MASK) | options[j].opt;
1475 
1476          else
1477             display_log(dp, USER_ERROR,
1478       "%.*s: messages cannot be turned off individually; set a message level",
1479                   i, arg);
1480       }
1481 
1482       else if (options[j].opt < OPTION)
1483       {
1484          if (val)
1485             dp->options |= options[j].opt;
1486 
1487          else
1488             dp->options &= ~options[j].opt;
1489       }
1490 
1491       return 1; /* this is an option */
1492    }
1493 
1494    else
1495       return 0; /* not an option */
1496 }
1497 
1498 #ifdef PNG_PNGCP_TIMING_SUPPORTED
1499 static void
set_timer(struct display * dp,struct timespec * timer)1500 set_timer(struct display *dp, struct timespec *timer)
1501 {
1502    /* Do the timing using clock_gettime and the per-process timer. */
1503    if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, timer))
1504    {
1505       display_log(dp, APP_ERROR,
1506             "CLOCK_PROCESS_CPUTIME_ID: %s: timing disabled\n", strerror(errno));
1507       dp->value[OPTIND(dp,time)] = 0; /* i.e. off */
1508    }
1509 }
1510 
1511 static void
start_timer(struct display * dp,int what)1512 start_timer(struct display *dp, int what)
1513 {
1514    if ((dp->value[OPTIND(dp,time)] & what) != 0)
1515       set_timer(dp, what == PNGCP_TIME_READ ? &dp->read_time : &dp->write_time);
1516 }
1517 
1518 static void
end_timer(struct display * dp,int what)1519 end_timer(struct display *dp, int what)
1520 {
1521    if ((dp->value[OPTIND(dp,time)] & what) != 0)
1522    {
1523       struct timespec t, tmp;
1524 
1525       set_timer(dp, &t);
1526 
1527       if (what == PNGCP_TIME_READ)
1528          tmp = dp->read_time;
1529 
1530       else
1531          tmp = dp->write_time;
1532 
1533       t.tv_sec -= tmp.tv_sec;
1534       t.tv_nsec -= tmp.tv_nsec;
1535 
1536       if (t.tv_nsec < 0)
1537       {
1538          --(t.tv_sec);
1539          t.tv_nsec += 1000000000L;
1540       }
1541 
1542       if (what == PNGCP_TIME_READ)
1543          dp->read_time = t, tmp = dp->read_time_total;
1544 
1545       else
1546          dp->write_time = t, tmp = dp->write_time_total;
1547 
1548       tmp.tv_sec += t.tv_sec;
1549       tmp.tv_nsec += t.tv_nsec;
1550 
1551       if (tmp.tv_nsec >= 1000000000L)
1552       {
1553          ++(tmp.tv_sec);
1554          tmp.tv_nsec -= 1000000000L;
1555       }
1556 
1557       if (what == PNGCP_TIME_READ)
1558          dp->read_time_total = tmp;
1559 
1560       else
1561          dp->write_time_total = tmp;
1562    }
1563 }
1564 
1565 static void
print_time(const char * what,struct timespec t)1566 print_time(const char *what, struct timespec t)
1567 {
1568    printf("%s %.2lu.%.9ld", what, (unsigned long)t.tv_sec, t.tv_nsec);
1569 }
1570 #else /* !PNGCP_TIMING */
1571 #define start_timer(dp, what) ((void)0)
1572 #define end_timer(dp, what) ((void)0)
1573 #endif /* !PNGCP_TIMING */
1574 
1575 /* The following is used in main to verify that the final argument is a
1576  * directory:
1577  */
1578 static int
checkdir(const char * pathname)1579 checkdir(const char *pathname)
1580 {
1581    struct stat buf;
1582    return stat(pathname, &buf) == 0 && S_ISDIR(buf.st_mode);
1583 }
1584 
1585 /* Work out whether a path is valid (if not a display_log occurs), a directory
1586  * (1 is returned) or a file *or* non-existent (0 is returned).
1587  *
1588  * Used for a write path.
1589  */
1590 static int
isdir(struct display * dp,const char * pathname)1591 isdir(struct display *dp, const char *pathname)
1592 {
1593    if (pathname == NULL)
1594       return 0; /* stdout */
1595 
1596    else if (pathname[0] == 0)
1597       return 1; /* empty string */
1598 
1599    else
1600    {
1601       struct stat buf;
1602       int ret = stat(pathname, &buf);
1603 
1604       if (ret == 0) /* the entry exists */
1605       {
1606          if (S_ISDIR(buf.st_mode))
1607             return 1;
1608 
1609          /* Else expect an object that exists and can be written: */
1610          if (access(pathname, W_OK) != 0)
1611             display_log(dp, USER_ERROR, "%s: cannot be written (%s)", pathname,
1612                   strerror(errno));
1613 
1614          return 0; /* file (exists, can be written) */
1615       }
1616 
1617       else /* an error */
1618       {
1619          /* Non-existence is fine, other errors are not: */
1620          if (errno != ENOENT)
1621             display_log(dp, USER_ERROR, "%s: invalid output name (%s)",
1622                   pathname, strerror(errno));
1623 
1624          return 0; /* file (does not exist) */
1625       }
1626    }
1627 }
1628 
1629 static void
makename(struct display * dp,const char * dir,const char * infile)1630 makename(struct display *dp, const char *dir, const char *infile)
1631 {
1632    /* Make a name for an output file (and check it). */
1633    dp->namebuf[0] = 0;
1634 
1635    if (dir == NULL || infile == NULL)
1636       display_log(dp, INTERNAL_ERROR, "NULL name to makename");
1637 
1638    else
1639    {
1640       size_t dsize = strlen(dir);
1641 
1642       if (dsize <= (sizeof dp->namebuf)-2) /* Allow for name + '/' + '\0' */
1643       {
1644          size_t isize = strlen(infile);
1645          size_t istart = isize-1;
1646 
1647          /* This should fail before here: */
1648          if (infile[istart] == '/')
1649             display_log(dp, INTERNAL_ERROR, "infile with trailing /");
1650 
1651          memcpy(dp->namebuf, dir, dsize);
1652          if (dsize > 0 && dp->namebuf[dsize-1] != '/')
1653             dp->namebuf[dsize++] = '/';
1654 
1655          /* Find the rightmost non-/ character: */
1656          while (istart > 0 && infile[istart-1] != '/')
1657             --istart;
1658 
1659          isize -= istart;
1660          infile += istart;
1661 
1662          if (dsize+isize < (sizeof dp->namebuf)) /* dsize + infile + '\0' */
1663          {
1664             memcpy(dp->namebuf+dsize, infile, isize+1);
1665 
1666             if (isdir(dp, dp->namebuf))
1667                display_log(dp, USER_ERROR, "%s: output file is a directory",
1668                      dp->namebuf);
1669          }
1670 
1671          else
1672          {
1673             dp->namebuf[dsize] = 0; /* allowed for: -2 at start */
1674             display_log(dp, USER_ERROR, "%s%s: output file name too long",
1675                   dp->namebuf, infile);
1676          }
1677       }
1678 
1679       else
1680          display_log(dp, USER_ERROR, "%s: output directory name too long", dir);
1681    }
1682 }
1683 
1684 /* error handler callbacks for libpng */
1685 static void PNGCBAPI
display_warning(png_structp pp,png_const_charp warning)1686 display_warning(png_structp pp, png_const_charp warning)
1687 {
1688    struct display *dp = get_dp(pp);
1689 
1690    /* This is used to prevent repeated warnings while searching */
1691    if (!dp->no_warnings)
1692       display_log(get_dp(pp), LIBPNG_WARNING, "%s", warning);
1693 }
1694 
1695 static void PNGCBAPI
display_error(png_structp pp,png_const_charp error)1696 display_error(png_structp pp, png_const_charp error)
1697 {
1698    struct display *dp = get_dp(pp);
1699 
1700    display_log(dp, LIBPNG_ERROR, "%s", error);
1701 }
1702 
1703 static void
display_start_read(struct display * dp,const char * filename)1704 display_start_read(struct display *dp, const char *filename)
1705 {
1706    if (filename != NULL)
1707    {
1708       dp->filename = filename;
1709       dp->fp = fopen(filename, "rb");
1710    }
1711 
1712    else
1713    {
1714       dp->filename = "<stdin>";
1715       dp->fp = stdin;
1716    }
1717 
1718    dp->w = dp->h = 0U;
1719    dp->bpp = 0U;
1720    dp->size = 0U;
1721    dp->read_size = 0U;
1722 
1723    if (dp->fp == NULL)
1724       display_log(dp, USER_ERROR, "file open failed (%s)", strerror(errno));
1725 }
1726 
1727 static void PNGCBAPI
read_function(png_structp pp,png_bytep data,png_size_t size)1728 read_function(png_structp pp, png_bytep data, png_size_t size)
1729 {
1730    struct display *dp = get_dp(pp);
1731 
1732    if (size == 0U || fread(data, size, 1U, dp->fp) == 1U)
1733       dp->read_size += size;
1734 
1735    else
1736    {
1737       if (feof(dp->fp))
1738          display_log(dp, LIBPNG_ERROR, "PNG file truncated");
1739       else
1740          display_log(dp, LIBPNG_ERROR, "PNG file read failed (%s)",
1741                strerror(errno));
1742    }
1743 }
1744 
1745 static void
read_png(struct display * dp,const char * filename)1746 read_png(struct display *dp, const char *filename)
1747 {
1748    display_clean_read(dp); /* safety */
1749    display_start_read(dp, filename);
1750 
1751    dp->read_pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp,
1752       display_error, display_warning);
1753    if (dp->read_pp == NULL)
1754       display_log(dp, LIBPNG_ERROR, "failed to create read struct");
1755 
1756 #  ifdef PNG_BENIGN_ERRORS_SUPPORTED
1757       png_set_benign_errors(dp->read_pp, 1/*allowed*/);
1758 #  endif /* BENIGN_ERRORS */
1759 
1760 #  ifdef FIX_INDEX
1761       if ((dp->options & FIX_INDEX) != 0)
1762          png_set_check_for_invalid_index(dp->read_pp, 1/*on, no warning*/);
1763 #     ifdef IGNORE_INDEX
1764          else
1765 #     endif /* IGNORE_INDEX */
1766 #  endif /* FIX_INDEX */
1767 #  ifdef IGNORE_INDEX
1768       if ((dp->options & IGNORE_INDEX) != 0) /* DANGEROUS */
1769          png_set_check_for_invalid_index(dp->read_pp, -1/*off completely*/);
1770 #  endif /* IGNORE_INDEX */
1771 
1772    /* The png_read_png API requires us to make the info struct, but it does the
1773     * call to png_read_info.
1774     */
1775    dp->ip = png_create_info_struct(dp->read_pp);
1776    if (dp->ip == NULL)
1777       png_error(dp->read_pp, "failed to create info struct");
1778 
1779    /* Set the IO handling */
1780    png_set_read_fn(dp->read_pp, dp, read_function);
1781 
1782 #  ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1783       png_set_keep_unknown_chunks(dp->read_pp, PNG_HANDLE_CHUNK_ALWAYS, NULL,
1784             0);
1785 #  endif /* HANDLE_AS_UNKNOWN */
1786 
1787 #  ifdef PNG_SET_USER_LIMITS_SUPPORTED
1788       /* Remove the user limits, if any */
1789       png_set_user_limits(dp->read_pp, 0x7fffffff, 0x7fffffff);
1790 #  endif /* SET_USER_LIMITS */
1791 
1792    /* Now read the PNG. */
1793    start_timer(dp, PNGCP_TIME_READ);
1794    png_read_png(dp->read_pp, dp->ip, 0U/*transforms*/, NULL/*params*/);
1795    end_timer(dp, PNGCP_TIME_READ);
1796    dp->w = png_get_image_width(dp->read_pp, dp->ip);
1797    dp->h = png_get_image_height(dp->read_pp, dp->ip);
1798    dp->ct = png_get_color_type(dp->read_pp, dp->ip);
1799    dp->bpp = png_get_bit_depth(dp->read_pp, dp->ip) *
1800              png_get_channels(dp->read_pp, dp->ip);
1801    {
1802       /* png_get_rowbytes should never return 0 because the value is set by the
1803        * first call to png_set_IHDR, which should have happened by now, but just
1804        * in case:
1805        */
1806       png_alloc_size_t rb = png_get_rowbytes(dp->read_pp, dp->ip);
1807 
1808       if (rb == 0)
1809          png_error(dp->read_pp, "invalid row byte count from libpng");
1810 
1811       /* The size calc can overflow. */
1812       if ((MAX_SIZE-dp->h)/rb < dp->h)
1813          png_error(dp->read_pp, "image too large");
1814 
1815       dp->size = rb * dp->h + dp->h/*filter byte*/;
1816    }
1817 
1818 #ifdef FIX_INDEX
1819    if (dp->ct == PNG_COLOR_TYPE_PALETTE && (dp->options & FIX_INDEX) != 0)
1820    {
1821       int max = png_get_palette_max(dp->read_pp, dp->ip);
1822       png_colorp palette = NULL;
1823       int num = -1;
1824 
1825       if (png_get_PLTE(dp->read_pp, dp->ip, &palette, &num) != PNG_INFO_PLTE
1826           || max < 0 || num <= 0 || palette == NULL)
1827          display_log(dp, LIBPNG_ERROR, "invalid png_get_PLTE result");
1828 
1829       if (max >= num)
1830       {
1831          /* 'Fix' the palette. */
1832          int i;
1833          png_color newpal[256];
1834 
1835          for (i=0; i<num; ++i)
1836             newpal[i] = palette[i];
1837 
1838          /* Fill in any remainder with a warning color: */
1839          for (; i<=max; ++i)
1840          {
1841             newpal[i].red = 0xbe;
1842             newpal[i].green = 0xad;
1843             newpal[i].blue = 0xed;
1844          }
1845 
1846          png_set_PLTE(dp->read_pp, dp->ip, newpal, i);
1847       }
1848    }
1849 #endif /* FIX_INDEX */
1850 
1851    display_clean_read(dp);
1852    dp->operation = "none";
1853 }
1854 
1855 static void
display_start_write(struct display * dp,const char * filename)1856 display_start_write(struct display *dp, const char *filename)
1857 {
1858    assert(dp->fp == NULL);
1859 
1860    if ((dp->options & NOWRITE) != 0)
1861       dp->output_file = "<no write>";
1862 
1863    else
1864    {
1865       if (filename != NULL)
1866       {
1867          dp->output_file = filename;
1868          dp->fp = fopen(filename, "wb");
1869       }
1870 
1871       else
1872       {
1873          dp->output_file = "<stdout>";
1874          dp->fp = stdout;
1875       }
1876 
1877       if (dp->fp == NULL)
1878          display_log(dp, USER_ERROR, "%s: file open failed (%s)",
1879                dp->output_file, strerror(errno));
1880    }
1881 }
1882 
1883 static void PNGCBAPI
write_function(png_structp pp,png_bytep data,png_size_t size)1884 write_function(png_structp pp, png_bytep data, png_size_t size)
1885 {
1886    struct display *dp = get_dp(pp);
1887 
1888    /* The write fail is classed as a USER_ERROR, so --quiet does not turn it
1889     * off, this seems more likely to be correct.
1890     */
1891    if (dp->fp == NULL || fwrite(data, size, 1U, dp->fp) == 1U)
1892    {
1893       dp->write_size += size;
1894       if (dp->write_size < size || dp->write_size == MAX_SIZE)
1895          png_error(pp, "IDAT size overflow");
1896    }
1897 
1898    else
1899       display_log(dp, USER_ERROR, "%s: PNG file write failed (%s)",
1900             dp->output_file, strerror(errno));
1901 }
1902 
1903 /* Compression option, 'method' is never set: there is no choice.
1904  *
1905  * IMPORTANT: the order of the entries in this macro determines the preference
1906  * order when two different combos of two of these options produce an IDAT of
1907  * the same size.  The logic here is to put the things that affect the decoding
1908  * of the PNG image ahead of those that are relevant only to the encoding.
1909  */
1910 #define SET_COMPRESSION\
1911    SET(strategy, strategy);\
1912    SET(windowBits, window_bits);\
1913    SET(level, level);\
1914    SET(memLevel, mem_level);
1915 
1916 #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
1917 static void
search_compression(struct display * dp)1918 search_compression(struct display *dp)
1919 {
1920    /* Like set_compression below but use a more restricted search than 'all' */
1921    int val;
1922 
1923 #  define SET(name, func) if (getsearchopts(dp, #name, &val))\
1924       png_set_compression_ ## func(dp->write_pp, val);
1925    SET_COMPRESSION
1926 #  undef SET
1927 }
1928 
1929 static void
set_compression(struct display * dp)1930 set_compression(struct display *dp)
1931 {
1932    int val;
1933 
1934 #  define SET(name, func) if (getallopts(dp, #name, &val))\
1935       png_set_compression_ ## func(dp->write_pp, val);
1936    SET_COMPRESSION
1937 #  undef SET
1938 }
1939 
1940 #ifdef PNG_SW_COMPRESS_level /* 1.7.0+ */
1941 static void
set_ICC_profile_compression(struct display * dp)1942 set_ICC_profile_compression(struct display *dp)
1943 {
1944    int val;
1945 
1946 #  define SET(name, func) if (getallopts(dp, "ICC-profile-" #name, &val))\
1947       png_set_ICC_profile_compression_ ## func(dp->write_pp, val);
1948    SET_COMPRESSION
1949 #  undef SET
1950 }
1951 #else
1952 #  define set_ICC_profile_compression(dp) ((void)0)
1953 #endif
1954 #else
1955 #  define search_compression(dp) ((void)0)
1956 #  define set_compression(dp) ((void)0)
1957 #  define set_ICC_profile_compression(dp) ((void)0)
1958 #endif /* WRITE_CUSTOMIZE_COMPRESSION */
1959 
1960 #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
1961 static void
set_text_compression(struct display * dp)1962 set_text_compression(struct display *dp)
1963 {
1964    int val;
1965 
1966 #  define SET(name, func) if (getallopts(dp, "text-" #name, &val))\
1967       png_set_text_compression_ ## func(dp->write_pp, val);
1968    SET_COMPRESSION
1969 #  undef SET
1970 }
1971 #else
1972 #  define set_text_compression(dp) ((void)0)
1973 #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */
1974 
1975 static void
write_png(struct display * dp,const char * destname)1976 write_png(struct display *dp, const char *destname)
1977 {
1978    display_clean_write(dp); /* safety */
1979    display_start_write(dp, destname);
1980 
1981    dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp,
1982       display_error, display_warning);
1983 
1984    if (dp->write_pp == NULL)
1985       display_log(dp, LIBPNG_ERROR, "failed to create write png_struct");
1986 
1987 #  ifdef PNG_BENIGN_ERRORS_SUPPORTED
1988       png_set_benign_errors(dp->write_pp, 1/*allowed*/);
1989 #  endif /* BENIGN_ERRORS */
1990 
1991    png_set_write_fn(dp->write_pp, dp, write_function, NULL/*flush*/);
1992 
1993 #ifdef IGNORE_INDEX
1994    if ((dp->options & IGNORE_INDEX) != 0) /* DANGEROUS */
1995       png_set_check_for_invalid_index(dp->write_pp, -1/*off completely*/);
1996 #endif /* IGNORE_INDEX */
1997 
1998    /* Restore the text chunks when using libpng 1.6 or less; this is a macro
1999     * which expands to nothing in 1.7+  In earlier versions it tests
2000     * dp->text_stashed, which is only set (below) *after* the first write.
2001     */
2002    text_restore(dp);
2003 
2004 #  ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
2005       png_set_keep_unknown_chunks(dp->write_pp, PNG_HANDLE_CHUNK_ALWAYS, NULL,
2006             0);
2007 #  endif /* HANDLE_AS_UNKNOWN */
2008 
2009 #  ifdef PNG_SET_USER_LIMITS_SUPPORTED
2010       /* Remove the user limits, if any */
2011       png_set_user_limits(dp->write_pp, 0x7fffffff, 0x7fffffff);
2012 #  endif
2013 
2014    /* OPTION HANDLING */
2015    /* compression outputs, IDAT and zTXt/iTXt: */
2016    dp->tsp = dp->nsp;
2017    dp->nsp = dp->csp = 0;
2018 #  ifdef PNG_SW_COMPRESS_png_level
2019       {
2020          int val;
2021 
2022          /* This sets everything, but then the following options just override
2023           * the specific settings for ICC profiles and text.
2024           */
2025          if (getallopts(dp, "compression", &val))
2026             png_set_compression(dp->write_pp, val);
2027 
2028          if (getallopts(dp, "ICC-profile-compression", &val))
2029             png_set_ICC_profile_compression(dp->write_pp, val);
2030 
2031          if (getallopts(dp, "text-compression", &val))
2032             png_set_text_compression(dp->write_pp, val);
2033       }
2034 #  endif /* png_level support */
2035    if (dp->options & SEARCH)
2036       search_compression(dp);
2037    else
2038       set_compression(dp);
2039    set_ICC_profile_compression(dp);
2040    set_text_compression(dp);
2041 
2042    {
2043       int val;
2044 
2045       /* The permitted range is 1..0x7FFFFFFF, so the cast is safe */
2046       if (get_option(dp, "IDAT-size", &val))
2047          png_set_IDAT_size(dp->write_pp, val);
2048    }
2049 
2050    /* filter handling */
2051 #  ifdef PNG_WRITE_FILTER_SUPPORTED
2052       {
2053          int val;
2054 
2055          if (get_option(dp, "filter", &val))
2056             png_set_filter(dp->write_pp, PNG_FILTER_TYPE_BASE, val);
2057       }
2058 #  endif /* WRITE_FILTER */
2059 
2060    /* This just uses the 'read' info_struct directly, it contains the image. */
2061    dp->write_size = 0U;
2062    start_timer(dp, PNGCP_TIME_WRITE);
2063    png_write_png(dp->write_pp, dp->ip, 0U/*transforms*/, NULL/*params*/);
2064    end_timer(dp, PNGCP_TIME_WRITE);
2065 
2066    /* Make sure the file was written ok: */
2067    if (dp->fp != NULL)
2068    {
2069       FILE *fp = dp->fp;
2070       dp->fp = NULL;
2071       if (fclose(fp))
2072          display_log(dp, APP_ERROR, "%s: write failed (%s)",
2073                destname == NULL ? "stdout" : destname, strerror(errno));
2074    }
2075 
2076    /* Clean it on the way out - if control returns to the caller then the
2077     * written_file contains the required data.
2078     */
2079    display_clean_write(dp);
2080    dp->operation = "none";
2081 }
2082 
2083 static void
set_windowBits_hi(struct display * dp)2084 set_windowBits_hi(struct display *dp)
2085 {
2086    /* windowBits is in the range 8..15 but zlib maps '8' to '9' so it is only
2087     * worth using if the data size is 256 byte or less.
2088     */
2089    int wb = MAX_WBITS; /* for large images */
2090    int i = VLSIZE(windowBits_IDAT);
2091 
2092    while (wb > 8 && dp->size <= 1U<<(wb-1)) --wb;
2093 
2094    while (--i >= 0) if (VLNAME(windowBits_IDAT)[i].name == range_hi) break;
2095 
2096    assert(i > 1); /* vl_windowBits_IDAT always has a RANGE() */
2097    VLNAME(windowBits_IDAT)[i].value = wb;
2098 
2099    assert(VLNAME(windowBits_IDAT)[--i].name == range_lo);
2100    VLNAME(windowBits_IDAT)[i].value = wb > 8 ? 9 : 8;
2101 
2102    /* If wb == 8 then any search has been restricted to just one windowBits
2103     * entry.  Record that here to avoid producing a spurious app-level warning
2104     * above.
2105     */
2106    if (wb == 8)
2107       dp->min_windowBits = OPTIND(dp, windowBits);
2108 }
2109 
2110 static int
better_options(const struct display * dp)2111 better_options(const struct display *dp)
2112 {
2113    /* Are these options better than the best found so far?  Normally the
2114     * options are tested in preference order, best first, however when doing a
2115     * search operation on a range the range values are tested out of order.  In
2116     * that case preferable options will get tested later.
2117     *
2118     * This function looks through the stack from the bottom up looking for an
2119     * option that does not match the current best value.  When it finds one it
2120     * checks to see if it is more or less desireable and returns true or false
2121     * as appropriate.
2122     *
2123     * Notice that this means that the order options are pushed onto the stack
2124     * conveys a priority; lower/earlier options are more important than later
2125     * ones.
2126     */
2127    unsigned int sp;
2128 
2129    for (sp=0; sp<dp->csp; ++sp)
2130    {
2131       int c = compare_option(dp, sp);
2132 
2133       if (c < 0)
2134          return 0; /* worse */
2135 
2136       else if (c > 0)
2137          return 1; /* better */
2138    }
2139 
2140    assert(0 && "unreached");
2141 }
2142 
2143 static void
print_search_results(struct display * dp)2144 print_search_results(struct display *dp)
2145 {
2146    assert(dp->filename != NULL);
2147    printf("%s [%ld x %ld %d bpp %s, %lu bytes] %lu -> %lu with '%s'\n",
2148       dp->filename, (unsigned long)dp->w, (unsigned long)dp->h, dp->bpp,
2149       cts(dp->ct), (unsigned long)dp->size, (unsigned long)dp->read_size,
2150       (unsigned long)dp->best_size, dp->best);
2151    fflush(stdout);
2152 }
2153 
2154 static void
log_search(struct display * dp,unsigned int log_depth)2155 log_search(struct display *dp, unsigned int log_depth)
2156 {
2157    /* Log, and reset, the search so far: */
2158    if (dp->nsp/*next entry to change*/ <= log_depth)
2159    {
2160       print_search_results(dp);
2161       /* Start again with this entry: */
2162       dp->best_size = MAX_SIZE;
2163    }
2164 }
2165 
2166 static void
cp_one_file(struct display * dp,const char * filename,const char * destname)2167 cp_one_file(struct display *dp, const char *filename, const char *destname)
2168 {
2169    unsigned int log_depth;
2170 
2171    dp->filename = filename;
2172    dp->operation = "read";
2173    dp->no_warnings = 0;
2174 
2175    /* Read it then write it: */
2176    if (filename != NULL && access(filename, R_OK) != 0)
2177       display_log(dp, USER_ERROR, "%s: invalid file name (%s)",
2178             filename, strerror(errno));
2179 
2180    read_png(dp, filename);
2181 
2182    /* But 'destname' may be a directory. */
2183    dp->operation = "write";
2184 
2185    /* Limit the upper end of the windowBits range for this file */
2186    set_windowBits_hi(dp);
2187 
2188    /* For logging, depth to log: */
2189    {
2190       int val;
2191 
2192       if (get_option(dp, "log-depth", &val) && val >= 0)
2193          log_depth = (unsigned int)/*SAFE*/val;
2194 
2195       else
2196          log_depth = 0U;
2197    }
2198 
2199    if (destname != NULL) /* else stdout */
2200    {
2201       if (isdir(dp, destname))
2202       {
2203          makename(dp, destname, filename);
2204          destname = dp->namebuf;
2205       }
2206 
2207       else if (access(destname, W_OK) != 0 && errno != ENOENT)
2208          display_log(dp, USER_ERROR, "%s: invalid output name (%s)", destname,
2209                strerror(errno));
2210    }
2211 
2212    dp->nsp = 0;
2213    dp->curr[0] = 0; /* acts as a flag for the caller */
2214    dp->opt_string_start = 0;
2215    dp->best[0] = 0; /* safety */
2216    dp->best_size = MAX_SIZE;
2217    write_png(dp, destname);
2218 
2219    /* Initialize the 'best' fields: */
2220    strcpy(dp->best, dp->curr);
2221    dp->best_size = dp->write_size;
2222 
2223    if (dp->nsp > 0) /* interating over lists */
2224    {
2225       char *tmpname, tmpbuf[(sizeof dp->namebuf) + 4];
2226       assert(dp->curr[0] == ' ' && dp->tsp > 0);
2227 
2228       /* Cancel warnings on subsequent writes */
2229       log_search(dp, log_depth);
2230       dp->no_warnings = 1;
2231 
2232       /* Make a temporary name for the subsequent tests: */
2233       if (destname != NULL)
2234       {
2235          strcpy(tmpbuf, destname);
2236          strcat(tmpbuf, ".tmp"); /* space for .tmp allocated above */
2237          tmpname = tmpbuf;
2238       }
2239 
2240       else
2241          tmpname = NULL; /* stdout */
2242 
2243       /* Loop to find the best option. */
2244       do
2245       {
2246          write_png(dp, tmpname);
2247 
2248          /* And compare the sizes (the write function makes sure write_size
2249           * doesn't overflow.)
2250           */
2251          assert(dp->csp > 0);
2252 
2253          if (dp->write_size < dp->best_size ||
2254              (dp->write_size == dp->best_size && better_options(dp)))
2255          {
2256             if (destname != NULL && rename(tmpname, destname) != 0)
2257                display_log(dp, APP_ERROR, "rename %s %s failed (%s)", tmpname,
2258                      destname, strerror(errno));
2259 
2260             strcpy(dp->best, dp->curr);
2261             dp->best_size = dp->write_size;
2262          }
2263 
2264          else if (tmpname != NULL && unlink(tmpname) != 0)
2265             display_log(dp, APP_WARNING, "unlink %s failed (%s)", tmpname,
2266                   strerror(errno));
2267 
2268          log_search(dp, log_depth);
2269       }
2270       while (dp->nsp > 0);
2271 
2272       /* Do this for the 'sizes' option so that it reports the correct size. */
2273       dp->write_size = dp->best_size;
2274    }
2275 }
2276 
2277 static int
cppng(struct display * dp,const char * file,const char * gv dest)2278 cppng(struct display *dp, const char *file, const char *gv dest)
2279    /* Exists solely to isolate the setjmp clobbers which some versions of GCC
2280     * erroneously generate.
2281     */
2282 {
2283    int ret = setjmp(dp->error_return);
2284 
2285    if (ret == 0)
2286    {
2287       dp->errset = 1;
2288       cp_one_file(dp, file, dest);
2289       dp->errset = 0;
2290       return 0;
2291    }
2292 
2293    else
2294    {
2295       dp->errset = 0;
2296 
2297       if (ret < ERRORS) /* shouldn't longjmp on warnings */
2298          display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
2299 
2300       return ret;
2301    }
2302 }
2303 
2304 int
main(const int argc,const char * const * const argv)2305 main(const int argc, const char * const * const argv)
2306 {
2307    /* For each file on the command line test it with a range of transforms */
2308    int option_end;
2309    struct display d;
2310 
2311    display_init(&d);
2312 
2313    d.operation = "options";
2314    for (option_end = 1;
2315         option_end < argc && opt_check(&d, argv[option_end]);
2316         ++option_end)
2317    {
2318    }
2319 
2320    /* Do a quick check on the directory target case; when there are more than
2321     * two arguments the last one must be a directory.
2322     */
2323    if (!(d.options & NOWRITE) && option_end+2 < argc && !checkdir(argv[argc-1]))
2324    {
2325       fprintf(stderr,
2326             "pngcp: %s: directory required with more than two arguments\n",
2327             argv[argc-1]);
2328       return 99;
2329    }
2330 
2331    {
2332       int errors = 0;
2333       int i = option_end;
2334 
2335       /* Do this at least once; if there are no arguments stdin/stdout are used.
2336        */
2337       d.operation = "files";
2338       do
2339       {
2340          const char *infile = NULL;
2341          const char *outfile = NULL;
2342          int ret;
2343 
2344          if (i < argc)
2345          {
2346             infile = argv[i++];
2347             if (!(d.options & NOWRITE) && i < argc)
2348                outfile = argv[argc-1];
2349          }
2350 
2351          ret = cppng(&d, infile, outfile);
2352 
2353          if (ret)
2354          {
2355             if (ret > QUIET) /* abort on user or internal error */
2356                return 99;
2357 
2358             /* An error: the output is meaningless */
2359          }
2360 
2361          else if (d.best[0] != 0)
2362          {
2363             /* This result may already have been output, in which case best_size
2364              * has been reset.
2365              */
2366             if (d.best_size < MAX_SIZE)
2367                print_search_results(&d);
2368          }
2369 
2370          else if (d.options & SIZES)
2371          {
2372             printf("%s [%ld x %ld %d bpp %s, %lu bytes] %lu -> %lu [0x%lx]\n",
2373                   infile, (unsigned long)d.w, (unsigned long)d.h, d.bpp,
2374                   cts(d.ct), (unsigned long)d.size, (unsigned long)d.read_size,
2375                   (unsigned long)d.write_size, (unsigned long)d.results);
2376             fflush(stdout);
2377          }
2378 
2379          /* Here on any return, including failures, except user/internal issues
2380           */
2381          {
2382             const int pass = (d.options & STRICT) ?
2383                RESULT_STRICT(d.results) : RESULT_RELAXED(d.results);
2384 
2385             if (!pass)
2386                ++errors;
2387 
2388             if (d.options & LOG)
2389             {
2390                int j;
2391 
2392                printf("%s: pngcp", pass ? "PASS" : "FAIL");
2393 
2394                for (j=1; j<option_end; ++j)
2395                   printf(" %s", argv[j]);
2396 
2397                if (infile != NULL)
2398                   printf(" %s", infile);
2399 
2400 #              ifdef PNG_PNGCP_TIMING_SUPPORTED
2401                   /* When logging output the files for each file, if enabled. */
2402                   if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_READ) != 0)
2403                      print_time(" read", d.read_time);
2404 
2405                   if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_WRITE) != 0)
2406                      print_time(" write", d.write_time);
2407 #              endif /* PNGCP_TIMING */
2408 
2409                printf("\n");
2410                fflush(stdout);
2411             }
2412          }
2413 
2414          display_clean(&d);
2415       }
2416       while (i+!(d.options & NOWRITE) < argc);
2417          /* I.e. for write cases after the first time through the loop require
2418           * there to be at least two arguments left and for the last one to be a
2419           * directory (this was checked above).
2420           */
2421 
2422       /* Release allocated memory */
2423       display_destroy(&d);
2424 
2425 #     ifdef PNG_PNGCP_TIMING_SUPPORTED
2426          {
2427             int output = 0;
2428 
2429             if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_READ) != 0)
2430                print_time("read", d.read_time_total), output = 1;
2431 
2432             if ((d.value[OPTIND(&d,time)] & PNGCP_TIME_WRITE) != 0)
2433             {
2434                if (output) putchar(' ');
2435                print_time("write", d.write_time_total);
2436                output = 1;
2437             }
2438 
2439             if (output) putchar('\n');
2440          }
2441 #     endif /* PNGCP_TIMING */
2442 
2443       return errors != 0;
2444    }
2445 }
2446 #else /* !READ_PNG || !WRITE_PNG */
2447 int
main(void)2448 main(void)
2449 {
2450    fprintf(stderr, "pngcp: no support for png_read/write_image\n");
2451    return 77;
2452 }
2453 #endif /* !READ_PNG || !WRITE_PNG */
2454