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