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