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