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