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