xref: /aosp_15_r20/external/brotli/c/tools/brotli.c (revision f4ee7fba7774faf2a30f13154332c0a06550dbc4)
1*f4ee7fbaSAndroid Build Coastguard Worker /* Copyright 2014 Google Inc. All Rights Reserved.
2*f4ee7fbaSAndroid Build Coastguard Worker 
3*f4ee7fbaSAndroid Build Coastguard Worker    Distributed under MIT license.
4*f4ee7fbaSAndroid Build Coastguard Worker    See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5*f4ee7fbaSAndroid Build Coastguard Worker */
6*f4ee7fbaSAndroid Build Coastguard Worker 
7*f4ee7fbaSAndroid Build Coastguard Worker /* Command line interface for Brotli library. */
8*f4ee7fbaSAndroid Build Coastguard Worker 
9*f4ee7fbaSAndroid Build Coastguard Worker /* Mute strerror/strcpy warnings. */
10*f4ee7fbaSAndroid Build Coastguard Worker #if !defined(_CRT_SECURE_NO_WARNINGS)
11*f4ee7fbaSAndroid Build Coastguard Worker #define _CRT_SECURE_NO_WARNINGS
12*f4ee7fbaSAndroid Build Coastguard Worker #endif
13*f4ee7fbaSAndroid Build Coastguard Worker 
14*f4ee7fbaSAndroid Build Coastguard Worker #include <errno.h>
15*f4ee7fbaSAndroid Build Coastguard Worker #include <fcntl.h>
16*f4ee7fbaSAndroid Build Coastguard Worker #include <stdio.h>
17*f4ee7fbaSAndroid Build Coastguard Worker #include <stdlib.h>
18*f4ee7fbaSAndroid Build Coastguard Worker #include <string.h>
19*f4ee7fbaSAndroid Build Coastguard Worker #include <sys/stat.h>
20*f4ee7fbaSAndroid Build Coastguard Worker #include <sys/types.h>
21*f4ee7fbaSAndroid Build Coastguard Worker #include <time.h>
22*f4ee7fbaSAndroid Build Coastguard Worker 
23*f4ee7fbaSAndroid Build Coastguard Worker #include "../common/constants.h"
24*f4ee7fbaSAndroid Build Coastguard Worker #include "../common/version.h"
25*f4ee7fbaSAndroid Build Coastguard Worker #include <brotli/decode.h>
26*f4ee7fbaSAndroid Build Coastguard Worker #include <brotli/encode.h>
27*f4ee7fbaSAndroid Build Coastguard Worker 
28*f4ee7fbaSAndroid Build Coastguard Worker #if !defined(_WIN32)
29*f4ee7fbaSAndroid Build Coastguard Worker #include <unistd.h>
30*f4ee7fbaSAndroid Build Coastguard Worker #include <utime.h>
31*f4ee7fbaSAndroid Build Coastguard Worker #define MAKE_BINARY(FILENO) (FILENO)
32*f4ee7fbaSAndroid Build Coastguard Worker #else
33*f4ee7fbaSAndroid Build Coastguard Worker #include <io.h>
34*f4ee7fbaSAndroid Build Coastguard Worker #include <share.h>
35*f4ee7fbaSAndroid Build Coastguard Worker #include <sys/utime.h>
36*f4ee7fbaSAndroid Build Coastguard Worker 
37*f4ee7fbaSAndroid Build Coastguard Worker #define MAKE_BINARY(FILENO) (_setmode((FILENO), _O_BINARY), (FILENO))
38*f4ee7fbaSAndroid Build Coastguard Worker 
39*f4ee7fbaSAndroid Build Coastguard Worker #if !defined(__MINGW32__)
40*f4ee7fbaSAndroid Build Coastguard Worker #define STDIN_FILENO _fileno(stdin)
41*f4ee7fbaSAndroid Build Coastguard Worker #define STDOUT_FILENO _fileno(stdout)
42*f4ee7fbaSAndroid Build Coastguard Worker #define S_IRUSR S_IREAD
43*f4ee7fbaSAndroid Build Coastguard Worker #define S_IWUSR S_IWRITE
44*f4ee7fbaSAndroid Build Coastguard Worker #endif
45*f4ee7fbaSAndroid Build Coastguard Worker 
46*f4ee7fbaSAndroid Build Coastguard Worker #define fdopen _fdopen
47*f4ee7fbaSAndroid Build Coastguard Worker #define isatty _isatty
48*f4ee7fbaSAndroid Build Coastguard Worker #define unlink _unlink
49*f4ee7fbaSAndroid Build Coastguard Worker #define utimbuf _utimbuf
50*f4ee7fbaSAndroid Build Coastguard Worker #define utime _utime
51*f4ee7fbaSAndroid Build Coastguard Worker 
52*f4ee7fbaSAndroid Build Coastguard Worker #define fopen ms_fopen
53*f4ee7fbaSAndroid Build Coastguard Worker #define open ms_open
54*f4ee7fbaSAndroid Build Coastguard Worker 
55*f4ee7fbaSAndroid Build Coastguard Worker #define chmod(F, P) (0)
56*f4ee7fbaSAndroid Build Coastguard Worker #define chown(F, O, G) (0)
57*f4ee7fbaSAndroid Build Coastguard Worker 
58*f4ee7fbaSAndroid Build Coastguard Worker #if defined(_MSC_VER) && (_MSC_VER >= 1400)
59*f4ee7fbaSAndroid Build Coastguard Worker #define fseek _fseeki64
60*f4ee7fbaSAndroid Build Coastguard Worker #define ftell _ftelli64
61*f4ee7fbaSAndroid Build Coastguard Worker #endif
62*f4ee7fbaSAndroid Build Coastguard Worker 
ms_fopen(const char * filename,const char * mode)63*f4ee7fbaSAndroid Build Coastguard Worker static FILE* ms_fopen(const char* filename, const char* mode) {
64*f4ee7fbaSAndroid Build Coastguard Worker   FILE* result = 0;
65*f4ee7fbaSAndroid Build Coastguard Worker   fopen_s(&result, filename, mode);
66*f4ee7fbaSAndroid Build Coastguard Worker   return result;
67*f4ee7fbaSAndroid Build Coastguard Worker }
68*f4ee7fbaSAndroid Build Coastguard Worker 
ms_open(const char * filename,int oflag,int pmode)69*f4ee7fbaSAndroid Build Coastguard Worker static int ms_open(const char* filename, int oflag, int pmode) {
70*f4ee7fbaSAndroid Build Coastguard Worker   int result = -1;
71*f4ee7fbaSAndroid Build Coastguard Worker   _sopen_s(&result, filename, oflag | O_BINARY, _SH_DENYNO, pmode);
72*f4ee7fbaSAndroid Build Coastguard Worker   return result;
73*f4ee7fbaSAndroid Build Coastguard Worker }
74*f4ee7fbaSAndroid Build Coastguard Worker #endif  /* WIN32 */
75*f4ee7fbaSAndroid Build Coastguard Worker 
76*f4ee7fbaSAndroid Build Coastguard Worker typedef enum {
77*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_COMPRESS,
78*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_DECOMPRESS,
79*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_HELP,
80*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_INVALID,
81*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_TEST_INTEGRITY,
82*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_NOOP,
83*f4ee7fbaSAndroid Build Coastguard Worker   COMMAND_VERSION
84*f4ee7fbaSAndroid Build Coastguard Worker } Command;
85*f4ee7fbaSAndroid Build Coastguard Worker 
86*f4ee7fbaSAndroid Build Coastguard Worker #define DEFAULT_LGWIN 24
87*f4ee7fbaSAndroid Build Coastguard Worker #define DEFAULT_SUFFIX ".br"
88*f4ee7fbaSAndroid Build Coastguard Worker #define MAX_OPTIONS 20
89*f4ee7fbaSAndroid Build Coastguard Worker 
90*f4ee7fbaSAndroid Build Coastguard Worker typedef struct {
91*f4ee7fbaSAndroid Build Coastguard Worker   /* Parameters */
92*f4ee7fbaSAndroid Build Coastguard Worker   int quality;
93*f4ee7fbaSAndroid Build Coastguard Worker   int lgwin;
94*f4ee7fbaSAndroid Build Coastguard Worker   int verbosity;
95*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL force_overwrite;
96*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL junk_source;
97*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL copy_stat;
98*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL write_to_stdout;
99*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL test_integrity;
100*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL decompress;
101*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL large_window;
102*f4ee7fbaSAndroid Build Coastguard Worker   const char* output_path;
103*f4ee7fbaSAndroid Build Coastguard Worker   const char* suffix;
104*f4ee7fbaSAndroid Build Coastguard Worker   int not_input_indices[MAX_OPTIONS];
105*f4ee7fbaSAndroid Build Coastguard Worker   size_t longest_path_len;
106*f4ee7fbaSAndroid Build Coastguard Worker   size_t input_count;
107*f4ee7fbaSAndroid Build Coastguard Worker 
108*f4ee7fbaSAndroid Build Coastguard Worker   /* Inner state */
109*f4ee7fbaSAndroid Build Coastguard Worker   int argc;
110*f4ee7fbaSAndroid Build Coastguard Worker   char** argv;
111*f4ee7fbaSAndroid Build Coastguard Worker   char* modified_path;  /* Storage for path with appended / cut suffix */
112*f4ee7fbaSAndroid Build Coastguard Worker   int iterator;
113*f4ee7fbaSAndroid Build Coastguard Worker   int ignore;
114*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL iterator_error;
115*f4ee7fbaSAndroid Build Coastguard Worker   uint8_t* buffer;
116*f4ee7fbaSAndroid Build Coastguard Worker   uint8_t* input;
117*f4ee7fbaSAndroid Build Coastguard Worker   uint8_t* output;
118*f4ee7fbaSAndroid Build Coastguard Worker   const char* current_input_path;
119*f4ee7fbaSAndroid Build Coastguard Worker   const char* current_output_path;
120*f4ee7fbaSAndroid Build Coastguard Worker   int64_t input_file_length;  /* -1, if impossible to calculate */
121*f4ee7fbaSAndroid Build Coastguard Worker   FILE* fin;
122*f4ee7fbaSAndroid Build Coastguard Worker   FILE* fout;
123*f4ee7fbaSAndroid Build Coastguard Worker 
124*f4ee7fbaSAndroid Build Coastguard Worker   /* I/O buffers */
125*f4ee7fbaSAndroid Build Coastguard Worker   size_t available_in;
126*f4ee7fbaSAndroid Build Coastguard Worker   const uint8_t* next_in;
127*f4ee7fbaSAndroid Build Coastguard Worker   size_t available_out;
128*f4ee7fbaSAndroid Build Coastguard Worker   uint8_t* next_out;
129*f4ee7fbaSAndroid Build Coastguard Worker 
130*f4ee7fbaSAndroid Build Coastguard Worker   /* Reporting */
131*f4ee7fbaSAndroid Build Coastguard Worker   /* size_t would be large enough,
132*f4ee7fbaSAndroid Build Coastguard Worker      until 4GiB+ files are compressed / decompressed on 32-bit CPUs. */
133*f4ee7fbaSAndroid Build Coastguard Worker   size_t total_in;
134*f4ee7fbaSAndroid Build Coastguard Worker   size_t total_out;
135*f4ee7fbaSAndroid Build Coastguard Worker } Context;
136*f4ee7fbaSAndroid Build Coastguard Worker 
137*f4ee7fbaSAndroid Build Coastguard Worker /* Parse up to 5 decimal digits. */
ParseInt(const char * s,int low,int high,int * result)138*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL ParseInt(const char* s, int low, int high, int* result) {
139*f4ee7fbaSAndroid Build Coastguard Worker   int value = 0;
140*f4ee7fbaSAndroid Build Coastguard Worker   int i;
141*f4ee7fbaSAndroid Build Coastguard Worker   for (i = 0; i < 5; ++i) {
142*f4ee7fbaSAndroid Build Coastguard Worker     char c = s[i];
143*f4ee7fbaSAndroid Build Coastguard Worker     if (c == 0) break;
144*f4ee7fbaSAndroid Build Coastguard Worker     if (s[i] < '0' || s[i] > '9') return BROTLI_FALSE;
145*f4ee7fbaSAndroid Build Coastguard Worker     value = (10 * value) + (c - '0');
146*f4ee7fbaSAndroid Build Coastguard Worker   }
147*f4ee7fbaSAndroid Build Coastguard Worker   if (i == 0) return BROTLI_FALSE;
148*f4ee7fbaSAndroid Build Coastguard Worker   if (i > 1 && s[0] == '0') return BROTLI_FALSE;
149*f4ee7fbaSAndroid Build Coastguard Worker   if (s[i] != 0) return BROTLI_FALSE;
150*f4ee7fbaSAndroid Build Coastguard Worker   if (value < low || value > high) return BROTLI_FALSE;
151*f4ee7fbaSAndroid Build Coastguard Worker   *result = value;
152*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
153*f4ee7fbaSAndroid Build Coastguard Worker }
154*f4ee7fbaSAndroid Build Coastguard Worker 
155*f4ee7fbaSAndroid Build Coastguard Worker /* Returns "base file name" or its tail, if it contains '/' or '\'. */
FileName(const char * path)156*f4ee7fbaSAndroid Build Coastguard Worker static const char* FileName(const char* path) {
157*f4ee7fbaSAndroid Build Coastguard Worker   const char* separator_position = strrchr(path, '/');
158*f4ee7fbaSAndroid Build Coastguard Worker   if (separator_position) path = separator_position + 1;
159*f4ee7fbaSAndroid Build Coastguard Worker   separator_position = strrchr(path, '\\');
160*f4ee7fbaSAndroid Build Coastguard Worker   if (separator_position) path = separator_position + 1;
161*f4ee7fbaSAndroid Build Coastguard Worker   return path;
162*f4ee7fbaSAndroid Build Coastguard Worker }
163*f4ee7fbaSAndroid Build Coastguard Worker 
164*f4ee7fbaSAndroid Build Coastguard Worker /* Detect if the program name is a special alias that infers a command type. */
ParseAlias(const char * name)165*f4ee7fbaSAndroid Build Coastguard Worker static Command ParseAlias(const char* name) {
166*f4ee7fbaSAndroid Build Coastguard Worker   /* TODO: cast name to lower case? */
167*f4ee7fbaSAndroid Build Coastguard Worker   const char* unbrotli = "unbrotli";
168*f4ee7fbaSAndroid Build Coastguard Worker   size_t unbrotli_len = strlen(unbrotli);
169*f4ee7fbaSAndroid Build Coastguard Worker   name = FileName(name);
170*f4ee7fbaSAndroid Build Coastguard Worker   /* Partial comparison. On Windows there could be ".exe" suffix. */
171*f4ee7fbaSAndroid Build Coastguard Worker   if (strncmp(name, unbrotli, unbrotli_len) == 0) {
172*f4ee7fbaSAndroid Build Coastguard Worker     char terminator = name[unbrotli_len];
173*f4ee7fbaSAndroid Build Coastguard Worker     if (terminator == 0 || terminator == '.') return COMMAND_DECOMPRESS;
174*f4ee7fbaSAndroid Build Coastguard Worker   }
175*f4ee7fbaSAndroid Build Coastguard Worker   return COMMAND_COMPRESS;
176*f4ee7fbaSAndroid Build Coastguard Worker }
177*f4ee7fbaSAndroid Build Coastguard Worker 
ParseParams(Context * params)178*f4ee7fbaSAndroid Build Coastguard Worker static Command ParseParams(Context* params) {
179*f4ee7fbaSAndroid Build Coastguard Worker   int argc = params->argc;
180*f4ee7fbaSAndroid Build Coastguard Worker   char** argv = params->argv;
181*f4ee7fbaSAndroid Build Coastguard Worker   int i;
182*f4ee7fbaSAndroid Build Coastguard Worker   int next_option_index = 0;
183*f4ee7fbaSAndroid Build Coastguard Worker   size_t input_count = 0;
184*f4ee7fbaSAndroid Build Coastguard Worker   size_t longest_path_len = 1;
185*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL command_set = BROTLI_FALSE;
186*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL quality_set = BROTLI_FALSE;
187*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL output_set = BROTLI_FALSE;
188*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL keep_set = BROTLI_FALSE;
189*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL lgwin_set = BROTLI_FALSE;
190*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL suffix_set = BROTLI_FALSE;
191*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL after_dash_dash = BROTLI_FALSE;
192*f4ee7fbaSAndroid Build Coastguard Worker   Command command = ParseAlias(argv[0]);
193*f4ee7fbaSAndroid Build Coastguard Worker 
194*f4ee7fbaSAndroid Build Coastguard Worker   for (i = 1; i < argc; ++i) {
195*f4ee7fbaSAndroid Build Coastguard Worker     const char* arg = argv[i];
196*f4ee7fbaSAndroid Build Coastguard Worker     /* C99 5.1.2.2.1: "members argv[0] through argv[argc-1] inclusive shall
197*f4ee7fbaSAndroid Build Coastguard Worker        contain pointers to strings"; NULL and 0-length are not forbidden. */
198*f4ee7fbaSAndroid Build Coastguard Worker     size_t arg_len = arg ? strlen(arg) : 0;
199*f4ee7fbaSAndroid Build Coastguard Worker 
200*f4ee7fbaSAndroid Build Coastguard Worker     if (arg_len == 0) {
201*f4ee7fbaSAndroid Build Coastguard Worker       params->not_input_indices[next_option_index++] = i;
202*f4ee7fbaSAndroid Build Coastguard Worker       continue;
203*f4ee7fbaSAndroid Build Coastguard Worker     }
204*f4ee7fbaSAndroid Build Coastguard Worker 
205*f4ee7fbaSAndroid Build Coastguard Worker     /* Too many options. The expected longest option list is:
206*f4ee7fbaSAndroid Build Coastguard Worker        "-q 0 -w 10 -o f -D d -S b -d -f -k -n -v --", i.e. 16 items in total.
207*f4ee7fbaSAndroid Build Coastguard Worker        This check is an additional guard that is never triggered, but provides
208*f4ee7fbaSAndroid Build Coastguard Worker        a guard for future changes. */
209*f4ee7fbaSAndroid Build Coastguard Worker     if (next_option_index > (MAX_OPTIONS - 2)) {
210*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "too many options passed\n");
211*f4ee7fbaSAndroid Build Coastguard Worker       return COMMAND_INVALID;
212*f4ee7fbaSAndroid Build Coastguard Worker     }
213*f4ee7fbaSAndroid Build Coastguard Worker 
214*f4ee7fbaSAndroid Build Coastguard Worker     /* Input file entry. */
215*f4ee7fbaSAndroid Build Coastguard Worker     if (after_dash_dash || arg[0] != '-' || arg_len == 1) {
216*f4ee7fbaSAndroid Build Coastguard Worker       input_count++;
217*f4ee7fbaSAndroid Build Coastguard Worker       if (longest_path_len < arg_len) longest_path_len = arg_len;
218*f4ee7fbaSAndroid Build Coastguard Worker       continue;
219*f4ee7fbaSAndroid Build Coastguard Worker     }
220*f4ee7fbaSAndroid Build Coastguard Worker 
221*f4ee7fbaSAndroid Build Coastguard Worker     /* Not a file entry. */
222*f4ee7fbaSAndroid Build Coastguard Worker     params->not_input_indices[next_option_index++] = i;
223*f4ee7fbaSAndroid Build Coastguard Worker 
224*f4ee7fbaSAndroid Build Coastguard Worker     /* '--' entry stop parsing arguments. */
225*f4ee7fbaSAndroid Build Coastguard Worker     if (arg_len == 2 && arg[1] == '-') {
226*f4ee7fbaSAndroid Build Coastguard Worker       after_dash_dash = BROTLI_TRUE;
227*f4ee7fbaSAndroid Build Coastguard Worker       continue;
228*f4ee7fbaSAndroid Build Coastguard Worker     }
229*f4ee7fbaSAndroid Build Coastguard Worker 
230*f4ee7fbaSAndroid Build Coastguard Worker     /* Simple / coalesced options. */
231*f4ee7fbaSAndroid Build Coastguard Worker     if (arg[1] != '-') {
232*f4ee7fbaSAndroid Build Coastguard Worker       size_t j;
233*f4ee7fbaSAndroid Build Coastguard Worker       for (j = 1; j < arg_len; ++j) {
234*f4ee7fbaSAndroid Build Coastguard Worker         char c = arg[j];
235*f4ee7fbaSAndroid Build Coastguard Worker         if (c >= '0' && c <= '9') {
236*f4ee7fbaSAndroid Build Coastguard Worker           if (quality_set) {
237*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "quality already set\n");
238*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
239*f4ee7fbaSAndroid Build Coastguard Worker           }
240*f4ee7fbaSAndroid Build Coastguard Worker           quality_set = BROTLI_TRUE;
241*f4ee7fbaSAndroid Build Coastguard Worker           params->quality = c - '0';
242*f4ee7fbaSAndroid Build Coastguard Worker           continue;
243*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'c') {
244*f4ee7fbaSAndroid Build Coastguard Worker           if (output_set) {
245*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "write to standard output already set\n");
246*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
247*f4ee7fbaSAndroid Build Coastguard Worker           }
248*f4ee7fbaSAndroid Build Coastguard Worker           output_set = BROTLI_TRUE;
249*f4ee7fbaSAndroid Build Coastguard Worker           params->write_to_stdout = BROTLI_TRUE;
250*f4ee7fbaSAndroid Build Coastguard Worker           continue;
251*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'd') {
252*f4ee7fbaSAndroid Build Coastguard Worker           if (command_set) {
253*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "command already set when parsing -d\n");
254*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
255*f4ee7fbaSAndroid Build Coastguard Worker           }
256*f4ee7fbaSAndroid Build Coastguard Worker           command_set = BROTLI_TRUE;
257*f4ee7fbaSAndroid Build Coastguard Worker           command = COMMAND_DECOMPRESS;
258*f4ee7fbaSAndroid Build Coastguard Worker           continue;
259*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'f') {
260*f4ee7fbaSAndroid Build Coastguard Worker           if (params->force_overwrite) {
261*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "force output overwrite already set\n");
262*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
263*f4ee7fbaSAndroid Build Coastguard Worker           }
264*f4ee7fbaSAndroid Build Coastguard Worker           params->force_overwrite = BROTLI_TRUE;
265*f4ee7fbaSAndroid Build Coastguard Worker           continue;
266*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'h') {
267*f4ee7fbaSAndroid Build Coastguard Worker           /* Don't parse further. */
268*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_HELP;
269*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'j' || c == 'k') {
270*f4ee7fbaSAndroid Build Coastguard Worker           if (keep_set) {
271*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
272*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
273*f4ee7fbaSAndroid Build Coastguard Worker           }
274*f4ee7fbaSAndroid Build Coastguard Worker           keep_set = BROTLI_TRUE;
275*f4ee7fbaSAndroid Build Coastguard Worker           params->junk_source = TO_BROTLI_BOOL(c == 'j');
276*f4ee7fbaSAndroid Build Coastguard Worker           continue;
277*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'n') {
278*f4ee7fbaSAndroid Build Coastguard Worker           if (!params->copy_stat) {
279*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "argument --no-copy-stat / -n already set\n");
280*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
281*f4ee7fbaSAndroid Build Coastguard Worker           }
282*f4ee7fbaSAndroid Build Coastguard Worker           params->copy_stat = BROTLI_FALSE;
283*f4ee7fbaSAndroid Build Coastguard Worker           continue;
284*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 't') {
285*f4ee7fbaSAndroid Build Coastguard Worker           if (command_set) {
286*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "command already set when parsing -t\n");
287*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
288*f4ee7fbaSAndroid Build Coastguard Worker           }
289*f4ee7fbaSAndroid Build Coastguard Worker           command_set = BROTLI_TRUE;
290*f4ee7fbaSAndroid Build Coastguard Worker           command = COMMAND_TEST_INTEGRITY;
291*f4ee7fbaSAndroid Build Coastguard Worker           continue;
292*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'v') {
293*f4ee7fbaSAndroid Build Coastguard Worker           if (params->verbosity > 0) {
294*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "argument --verbose / -v already set\n");
295*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
296*f4ee7fbaSAndroid Build Coastguard Worker           }
297*f4ee7fbaSAndroid Build Coastguard Worker           params->verbosity = 1;
298*f4ee7fbaSAndroid Build Coastguard Worker           continue;
299*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'V') {
300*f4ee7fbaSAndroid Build Coastguard Worker           /* Don't parse further. */
301*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_VERSION;
302*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'Z') {
303*f4ee7fbaSAndroid Build Coastguard Worker           if (quality_set) {
304*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "quality already set\n");
305*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
306*f4ee7fbaSAndroid Build Coastguard Worker           }
307*f4ee7fbaSAndroid Build Coastguard Worker           quality_set = BROTLI_TRUE;
308*f4ee7fbaSAndroid Build Coastguard Worker           params->quality = 11;
309*f4ee7fbaSAndroid Build Coastguard Worker           continue;
310*f4ee7fbaSAndroid Build Coastguard Worker         }
311*f4ee7fbaSAndroid Build Coastguard Worker         /* o/q/w/D/S with parameter is expected */
312*f4ee7fbaSAndroid Build Coastguard Worker         if (c != 'o' && c != 'q' && c != 'w' && c != 'D' && c != 'S') {
313*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "invalid argument -%c\n", c);
314*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
315*f4ee7fbaSAndroid Build Coastguard Worker         }
316*f4ee7fbaSAndroid Build Coastguard Worker         if (j + 1 != arg_len) {
317*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "expected parameter for argument -%c\n", c);
318*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
319*f4ee7fbaSAndroid Build Coastguard Worker         }
320*f4ee7fbaSAndroid Build Coastguard Worker         i++;
321*f4ee7fbaSAndroid Build Coastguard Worker         if (i == argc || !argv[i] || argv[i][0] == 0) {
322*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "expected parameter for argument -%c\n", c);
323*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
324*f4ee7fbaSAndroid Build Coastguard Worker         }
325*f4ee7fbaSAndroid Build Coastguard Worker         params->not_input_indices[next_option_index++] = i;
326*f4ee7fbaSAndroid Build Coastguard Worker         if (c == 'o') {
327*f4ee7fbaSAndroid Build Coastguard Worker           if (output_set) {
328*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "write to standard output already set (-o)\n");
329*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
330*f4ee7fbaSAndroid Build Coastguard Worker           }
331*f4ee7fbaSAndroid Build Coastguard Worker           params->output_path = argv[i];
332*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'q') {
333*f4ee7fbaSAndroid Build Coastguard Worker           if (quality_set) {
334*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "quality already set\n");
335*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
336*f4ee7fbaSAndroid Build Coastguard Worker           }
337*f4ee7fbaSAndroid Build Coastguard Worker           quality_set = ParseInt(argv[i], BROTLI_MIN_QUALITY,
338*f4ee7fbaSAndroid Build Coastguard Worker                                  BROTLI_MAX_QUALITY, &params->quality);
339*f4ee7fbaSAndroid Build Coastguard Worker           if (!quality_set) {
340*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "error parsing quality value [%s]\n", argv[i]);
341*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
342*f4ee7fbaSAndroid Build Coastguard Worker           }
343*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'w') {
344*f4ee7fbaSAndroid Build Coastguard Worker           if (lgwin_set) {
345*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "lgwin parameter already set\n");
346*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
347*f4ee7fbaSAndroid Build Coastguard Worker           }
348*f4ee7fbaSAndroid Build Coastguard Worker           lgwin_set = ParseInt(argv[i], 0,
349*f4ee7fbaSAndroid Build Coastguard Worker                                BROTLI_MAX_WINDOW_BITS, &params->lgwin);
350*f4ee7fbaSAndroid Build Coastguard Worker           if (!lgwin_set) {
351*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "error parsing lgwin value [%s]\n", argv[i]);
352*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
353*f4ee7fbaSAndroid Build Coastguard Worker           }
354*f4ee7fbaSAndroid Build Coastguard Worker           if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
355*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr,
356*f4ee7fbaSAndroid Build Coastguard Worker                     "lgwin parameter (%d) smaller than the minimum (%d)\n",
357*f4ee7fbaSAndroid Build Coastguard Worker                     params->lgwin, BROTLI_MIN_WINDOW_BITS);
358*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
359*f4ee7fbaSAndroid Build Coastguard Worker           }
360*f4ee7fbaSAndroid Build Coastguard Worker         } else if (c == 'S') {
361*f4ee7fbaSAndroid Build Coastguard Worker           if (suffix_set) {
362*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "suffix already set\n");
363*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
364*f4ee7fbaSAndroid Build Coastguard Worker           }
365*f4ee7fbaSAndroid Build Coastguard Worker           suffix_set = BROTLI_TRUE;
366*f4ee7fbaSAndroid Build Coastguard Worker           params->suffix = argv[i];
367*f4ee7fbaSAndroid Build Coastguard Worker         }
368*f4ee7fbaSAndroid Build Coastguard Worker       }
369*f4ee7fbaSAndroid Build Coastguard Worker     } else {  /* Double-dash. */
370*f4ee7fbaSAndroid Build Coastguard Worker       arg = &arg[2];
371*f4ee7fbaSAndroid Build Coastguard Worker       if (strcmp("best", arg) == 0) {
372*f4ee7fbaSAndroid Build Coastguard Worker         if (quality_set) {
373*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "quality already set\n");
374*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
375*f4ee7fbaSAndroid Build Coastguard Worker         }
376*f4ee7fbaSAndroid Build Coastguard Worker         quality_set = BROTLI_TRUE;
377*f4ee7fbaSAndroid Build Coastguard Worker         params->quality = 11;
378*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("decompress", arg) == 0) {
379*f4ee7fbaSAndroid Build Coastguard Worker         if (command_set) {
380*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "command already set when parsing --decompress\n");
381*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
382*f4ee7fbaSAndroid Build Coastguard Worker         }
383*f4ee7fbaSAndroid Build Coastguard Worker         command_set = BROTLI_TRUE;
384*f4ee7fbaSAndroid Build Coastguard Worker         command = COMMAND_DECOMPRESS;
385*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("force", arg) == 0) {
386*f4ee7fbaSAndroid Build Coastguard Worker         if (params->force_overwrite) {
387*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "force output overwrite already set\n");
388*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
389*f4ee7fbaSAndroid Build Coastguard Worker         }
390*f4ee7fbaSAndroid Build Coastguard Worker         params->force_overwrite = BROTLI_TRUE;
391*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("help", arg) == 0) {
392*f4ee7fbaSAndroid Build Coastguard Worker         /* Don't parse further. */
393*f4ee7fbaSAndroid Build Coastguard Worker         return COMMAND_HELP;
394*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("keep", arg) == 0) {
395*f4ee7fbaSAndroid Build Coastguard Worker         if (keep_set) {
396*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
397*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
398*f4ee7fbaSAndroid Build Coastguard Worker         }
399*f4ee7fbaSAndroid Build Coastguard Worker         keep_set = BROTLI_TRUE;
400*f4ee7fbaSAndroid Build Coastguard Worker         params->junk_source = BROTLI_FALSE;
401*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("no-copy-stat", arg) == 0) {
402*f4ee7fbaSAndroid Build Coastguard Worker         if (!params->copy_stat) {
403*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "argument --no-copy-stat / -n already set\n");
404*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
405*f4ee7fbaSAndroid Build Coastguard Worker         }
406*f4ee7fbaSAndroid Build Coastguard Worker         params->copy_stat = BROTLI_FALSE;
407*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("rm", arg) == 0) {
408*f4ee7fbaSAndroid Build Coastguard Worker         if (keep_set) {
409*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "argument --rm / -j or --keep / -k already set\n");
410*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
411*f4ee7fbaSAndroid Build Coastguard Worker         }
412*f4ee7fbaSAndroid Build Coastguard Worker         keep_set = BROTLI_TRUE;
413*f4ee7fbaSAndroid Build Coastguard Worker         params->junk_source = BROTLI_TRUE;
414*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("stdout", arg) == 0) {
415*f4ee7fbaSAndroid Build Coastguard Worker         if (output_set) {
416*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "write to standard output already set\n");
417*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
418*f4ee7fbaSAndroid Build Coastguard Worker         }
419*f4ee7fbaSAndroid Build Coastguard Worker         output_set = BROTLI_TRUE;
420*f4ee7fbaSAndroid Build Coastguard Worker         params->write_to_stdout = BROTLI_TRUE;
421*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("test", arg) == 0) {
422*f4ee7fbaSAndroid Build Coastguard Worker         if (command_set) {
423*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "command already set when parsing --test\n");
424*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
425*f4ee7fbaSAndroid Build Coastguard Worker         }
426*f4ee7fbaSAndroid Build Coastguard Worker         command_set = BROTLI_TRUE;
427*f4ee7fbaSAndroid Build Coastguard Worker         command = COMMAND_TEST_INTEGRITY;
428*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("verbose", arg) == 0) {
429*f4ee7fbaSAndroid Build Coastguard Worker         if (params->verbosity > 0) {
430*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "argument --verbose / -v already set\n");
431*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
432*f4ee7fbaSAndroid Build Coastguard Worker         }
433*f4ee7fbaSAndroid Build Coastguard Worker         params->verbosity = 1;
434*f4ee7fbaSAndroid Build Coastguard Worker       } else if (strcmp("version", arg) == 0) {
435*f4ee7fbaSAndroid Build Coastguard Worker         /* Don't parse further. */
436*f4ee7fbaSAndroid Build Coastguard Worker         return COMMAND_VERSION;
437*f4ee7fbaSAndroid Build Coastguard Worker       } else {
438*f4ee7fbaSAndroid Build Coastguard Worker         /* key=value */
439*f4ee7fbaSAndroid Build Coastguard Worker         const char* value = strrchr(arg, '=');
440*f4ee7fbaSAndroid Build Coastguard Worker         size_t key_len;
441*f4ee7fbaSAndroid Build Coastguard Worker         if (!value || value[1] == 0) {
442*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "must pass the parameter as --%s=value\n", arg);
443*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
444*f4ee7fbaSAndroid Build Coastguard Worker         }
445*f4ee7fbaSAndroid Build Coastguard Worker         key_len = (size_t)(value - arg);
446*f4ee7fbaSAndroid Build Coastguard Worker         value++;
447*f4ee7fbaSAndroid Build Coastguard Worker         if (strncmp("lgwin", arg, key_len) == 0) {
448*f4ee7fbaSAndroid Build Coastguard Worker           if (lgwin_set) {
449*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "lgwin parameter already set\n");
450*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
451*f4ee7fbaSAndroid Build Coastguard Worker           }
452*f4ee7fbaSAndroid Build Coastguard Worker           lgwin_set = ParseInt(value, 0,
453*f4ee7fbaSAndroid Build Coastguard Worker                                BROTLI_MAX_WINDOW_BITS, &params->lgwin);
454*f4ee7fbaSAndroid Build Coastguard Worker           if (!lgwin_set) {
455*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "error parsing lgwin value [%s]\n", value);
456*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
457*f4ee7fbaSAndroid Build Coastguard Worker           }
458*f4ee7fbaSAndroid Build Coastguard Worker           if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
459*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr,
460*f4ee7fbaSAndroid Build Coastguard Worker                     "lgwin parameter (%d) smaller than the minimum (%d)\n",
461*f4ee7fbaSAndroid Build Coastguard Worker                     params->lgwin, BROTLI_MIN_WINDOW_BITS);
462*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
463*f4ee7fbaSAndroid Build Coastguard Worker           }
464*f4ee7fbaSAndroid Build Coastguard Worker         } else if (strncmp("large_window", arg, key_len) == 0) {
465*f4ee7fbaSAndroid Build Coastguard Worker           /* This option is intentionally not mentioned in help. */
466*f4ee7fbaSAndroid Build Coastguard Worker           if (lgwin_set) {
467*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "lgwin parameter already set\n");
468*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
469*f4ee7fbaSAndroid Build Coastguard Worker           }
470*f4ee7fbaSAndroid Build Coastguard Worker           lgwin_set = ParseInt(value, 0,
471*f4ee7fbaSAndroid Build Coastguard Worker                                BROTLI_LARGE_MAX_WINDOW_BITS, &params->lgwin);
472*f4ee7fbaSAndroid Build Coastguard Worker           if (!lgwin_set) {
473*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "error parsing lgwin value [%s]\n", value);
474*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
475*f4ee7fbaSAndroid Build Coastguard Worker           }
476*f4ee7fbaSAndroid Build Coastguard Worker           if (params->lgwin != 0 && params->lgwin < BROTLI_MIN_WINDOW_BITS) {
477*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr,
478*f4ee7fbaSAndroid Build Coastguard Worker                     "lgwin parameter (%d) smaller than the minimum (%d)\n",
479*f4ee7fbaSAndroid Build Coastguard Worker                     params->lgwin, BROTLI_MIN_WINDOW_BITS);
480*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
481*f4ee7fbaSAndroid Build Coastguard Worker           }
482*f4ee7fbaSAndroid Build Coastguard Worker         } else if (strncmp("output", arg, key_len) == 0) {
483*f4ee7fbaSAndroid Build Coastguard Worker           if (output_set) {
484*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr,
485*f4ee7fbaSAndroid Build Coastguard Worker                     "write to standard output already set (--output)\n");
486*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
487*f4ee7fbaSAndroid Build Coastguard Worker           }
488*f4ee7fbaSAndroid Build Coastguard Worker           params->output_path = value;
489*f4ee7fbaSAndroid Build Coastguard Worker         } else if (strncmp("quality", arg, key_len) == 0) {
490*f4ee7fbaSAndroid Build Coastguard Worker           if (quality_set) {
491*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "quality already set\n");
492*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
493*f4ee7fbaSAndroid Build Coastguard Worker           }
494*f4ee7fbaSAndroid Build Coastguard Worker           quality_set = ParseInt(value, BROTLI_MIN_QUALITY,
495*f4ee7fbaSAndroid Build Coastguard Worker                                  BROTLI_MAX_QUALITY, &params->quality);
496*f4ee7fbaSAndroid Build Coastguard Worker           if (!quality_set) {
497*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "error parsing quality value [%s]\n", value);
498*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
499*f4ee7fbaSAndroid Build Coastguard Worker           }
500*f4ee7fbaSAndroid Build Coastguard Worker         } else if (strncmp("suffix", arg, key_len) == 0) {
501*f4ee7fbaSAndroid Build Coastguard Worker           if (suffix_set) {
502*f4ee7fbaSAndroid Build Coastguard Worker             fprintf(stderr, "suffix already set\n");
503*f4ee7fbaSAndroid Build Coastguard Worker             return COMMAND_INVALID;
504*f4ee7fbaSAndroid Build Coastguard Worker           }
505*f4ee7fbaSAndroid Build Coastguard Worker           suffix_set = BROTLI_TRUE;
506*f4ee7fbaSAndroid Build Coastguard Worker           params->suffix = value;
507*f4ee7fbaSAndroid Build Coastguard Worker         } else {
508*f4ee7fbaSAndroid Build Coastguard Worker           fprintf(stderr, "invalid parameter: [%s]\n", arg);
509*f4ee7fbaSAndroid Build Coastguard Worker           return COMMAND_INVALID;
510*f4ee7fbaSAndroid Build Coastguard Worker         }
511*f4ee7fbaSAndroid Build Coastguard Worker       }
512*f4ee7fbaSAndroid Build Coastguard Worker     }
513*f4ee7fbaSAndroid Build Coastguard Worker   }
514*f4ee7fbaSAndroid Build Coastguard Worker 
515*f4ee7fbaSAndroid Build Coastguard Worker   params->input_count = input_count;
516*f4ee7fbaSAndroid Build Coastguard Worker   params->longest_path_len = longest_path_len;
517*f4ee7fbaSAndroid Build Coastguard Worker   params->decompress = (command == COMMAND_DECOMPRESS);
518*f4ee7fbaSAndroid Build Coastguard Worker   params->test_integrity = (command == COMMAND_TEST_INTEGRITY);
519*f4ee7fbaSAndroid Build Coastguard Worker 
520*f4ee7fbaSAndroid Build Coastguard Worker   if (input_count > 1 && output_set) return COMMAND_INVALID;
521*f4ee7fbaSAndroid Build Coastguard Worker   if (params->test_integrity) {
522*f4ee7fbaSAndroid Build Coastguard Worker     if (params->output_path) return COMMAND_INVALID;
523*f4ee7fbaSAndroid Build Coastguard Worker     if (params->write_to_stdout) return COMMAND_INVALID;
524*f4ee7fbaSAndroid Build Coastguard Worker   }
525*f4ee7fbaSAndroid Build Coastguard Worker   if (strchr(params->suffix, '/') || strchr(params->suffix, '\\')) {
526*f4ee7fbaSAndroid Build Coastguard Worker     return COMMAND_INVALID;
527*f4ee7fbaSAndroid Build Coastguard Worker   }
528*f4ee7fbaSAndroid Build Coastguard Worker 
529*f4ee7fbaSAndroid Build Coastguard Worker   return command;
530*f4ee7fbaSAndroid Build Coastguard Worker }
531*f4ee7fbaSAndroid Build Coastguard Worker 
PrintVersion(void)532*f4ee7fbaSAndroid Build Coastguard Worker static void PrintVersion(void) {
533*f4ee7fbaSAndroid Build Coastguard Worker   int major = BROTLI_VERSION >> 24;
534*f4ee7fbaSAndroid Build Coastguard Worker   int minor = (BROTLI_VERSION >> 12) & 0xFFF;
535*f4ee7fbaSAndroid Build Coastguard Worker   int patch = BROTLI_VERSION & 0xFFF;
536*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(stdout, "brotli %d.%d.%d\n", major, minor, patch);
537*f4ee7fbaSAndroid Build Coastguard Worker }
538*f4ee7fbaSAndroid Build Coastguard Worker 
PrintHelp(const char * name,BROTLI_BOOL error)539*f4ee7fbaSAndroid Build Coastguard Worker static void PrintHelp(const char* name, BROTLI_BOOL error) {
540*f4ee7fbaSAndroid Build Coastguard Worker   FILE* media = error ? stderr : stdout;
541*f4ee7fbaSAndroid Build Coastguard Worker   /* String is cut to pieces with length less than 509, to conform C90 spec. */
542*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
543*f4ee7fbaSAndroid Build Coastguard Worker "Usage: %s [OPTION]... [FILE]...\n",
544*f4ee7fbaSAndroid Build Coastguard Worker           name);
545*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
546*f4ee7fbaSAndroid Build Coastguard Worker "Options:\n"
547*f4ee7fbaSAndroid Build Coastguard Worker "  -#                          compression level (0-9)\n"
548*f4ee7fbaSAndroid Build Coastguard Worker "  -c, --stdout                write on standard output\n"
549*f4ee7fbaSAndroid Build Coastguard Worker "  -d, --decompress            decompress\n"
550*f4ee7fbaSAndroid Build Coastguard Worker "  -f, --force                 force output file overwrite\n"
551*f4ee7fbaSAndroid Build Coastguard Worker "  -h, --help                  display this help and exit\n");
552*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
553*f4ee7fbaSAndroid Build Coastguard Worker "  -j, --rm                    remove source file(s)\n"
554*f4ee7fbaSAndroid Build Coastguard Worker "  -k, --keep                  keep source file(s) (default)\n"
555*f4ee7fbaSAndroid Build Coastguard Worker "  -n, --no-copy-stat          do not copy source file(s) attributes\n"
556*f4ee7fbaSAndroid Build Coastguard Worker "  -o FILE, --output=FILE      output file (only if 1 input file)\n");
557*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
558*f4ee7fbaSAndroid Build Coastguard Worker "  -q NUM, --quality=NUM       compression level (%d-%d)\n",
559*f4ee7fbaSAndroid Build Coastguard Worker           BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY);
560*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
561*f4ee7fbaSAndroid Build Coastguard Worker "  -t, --test                  test compressed file integrity\n"
562*f4ee7fbaSAndroid Build Coastguard Worker "  -v, --verbose               verbose mode\n");
563*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
564*f4ee7fbaSAndroid Build Coastguard Worker "  -w NUM, --lgwin=NUM         set LZ77 window size (0, %d-%d)\n"
565*f4ee7fbaSAndroid Build Coastguard Worker "                              window size = 2**NUM - 16\n"
566*f4ee7fbaSAndroid Build Coastguard Worker "                              0 lets compressor choose the optimal value\n",
567*f4ee7fbaSAndroid Build Coastguard Worker           BROTLI_MIN_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS);
568*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
569*f4ee7fbaSAndroid Build Coastguard Worker "  --large_window=NUM          use incompatible large-window brotli\n"
570*f4ee7fbaSAndroid Build Coastguard Worker "                              bitstream with window size (0, %d-%d)\n"
571*f4ee7fbaSAndroid Build Coastguard Worker "                              WARNING: this format is not compatible\n"
572*f4ee7fbaSAndroid Build Coastguard Worker "                              with brotli RFC 7932 and may not be\n"
573*f4ee7fbaSAndroid Build Coastguard Worker "                              decodable with regular brotli decoders\n",
574*f4ee7fbaSAndroid Build Coastguard Worker           BROTLI_MIN_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS);
575*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
576*f4ee7fbaSAndroid Build Coastguard Worker "  -S SUF, --suffix=SUF        output file suffix (default:'%s')\n",
577*f4ee7fbaSAndroid Build Coastguard Worker           DEFAULT_SUFFIX);
578*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(media,
579*f4ee7fbaSAndroid Build Coastguard Worker "  -V, --version               display version and exit\n"
580*f4ee7fbaSAndroid Build Coastguard Worker "  -Z, --best                  use best compression level (11) (default)\n"
581*f4ee7fbaSAndroid Build Coastguard Worker "Simple options could be coalesced, i.e. '-9kf' is equivalent to '-9 -k -f'.\n"
582*f4ee7fbaSAndroid Build Coastguard Worker "With no FILE, or when FILE is -, read standard input.\n"
583*f4ee7fbaSAndroid Build Coastguard Worker "All arguments after '--' are treated as files.\n");
584*f4ee7fbaSAndroid Build Coastguard Worker }
585*f4ee7fbaSAndroid Build Coastguard Worker 
PrintablePath(const char * path)586*f4ee7fbaSAndroid Build Coastguard Worker static const char* PrintablePath(const char* path) {
587*f4ee7fbaSAndroid Build Coastguard Worker   return path ? path : "con";
588*f4ee7fbaSAndroid Build Coastguard Worker }
589*f4ee7fbaSAndroid Build Coastguard Worker 
OpenInputFile(const char * input_path,FILE ** f)590*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL OpenInputFile(const char* input_path, FILE** f) {
591*f4ee7fbaSAndroid Build Coastguard Worker   *f = NULL;
592*f4ee7fbaSAndroid Build Coastguard Worker   if (!input_path) {
593*f4ee7fbaSAndroid Build Coastguard Worker     *f = fdopen(MAKE_BINARY(STDIN_FILENO), "rb");
594*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
595*f4ee7fbaSAndroid Build Coastguard Worker   }
596*f4ee7fbaSAndroid Build Coastguard Worker   *f = fopen(input_path, "rb");
597*f4ee7fbaSAndroid Build Coastguard Worker   if (!*f) {
598*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "failed to open input file [%s]: %s\n",
599*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(input_path), strerror(errno));
600*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_FALSE;
601*f4ee7fbaSAndroid Build Coastguard Worker   }
602*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
603*f4ee7fbaSAndroid Build Coastguard Worker }
604*f4ee7fbaSAndroid Build Coastguard Worker 
OpenOutputFile(const char * output_path,FILE ** f,BROTLI_BOOL force)605*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL OpenOutputFile(const char* output_path, FILE** f,
606*f4ee7fbaSAndroid Build Coastguard Worker                                   BROTLI_BOOL force) {
607*f4ee7fbaSAndroid Build Coastguard Worker   int fd;
608*f4ee7fbaSAndroid Build Coastguard Worker   *f = NULL;
609*f4ee7fbaSAndroid Build Coastguard Worker   if (!output_path) {
610*f4ee7fbaSAndroid Build Coastguard Worker     *f = fdopen(MAKE_BINARY(STDOUT_FILENO), "wb");
611*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
612*f4ee7fbaSAndroid Build Coastguard Worker   }
613*f4ee7fbaSAndroid Build Coastguard Worker   fd = open(output_path, O_CREAT | (force ? 0 : O_EXCL) | O_WRONLY | O_TRUNC,
614*f4ee7fbaSAndroid Build Coastguard Worker             S_IRUSR | S_IWUSR);
615*f4ee7fbaSAndroid Build Coastguard Worker   if (fd < 0) {
616*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "failed to open output file [%s]: %s\n",
617*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(output_path), strerror(errno));
618*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_FALSE;
619*f4ee7fbaSAndroid Build Coastguard Worker   }
620*f4ee7fbaSAndroid Build Coastguard Worker   *f = fdopen(fd, "wb");
621*f4ee7fbaSAndroid Build Coastguard Worker   if (!*f) {
622*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "failed to open output file [%s]: %s\n",
623*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(output_path), strerror(errno));
624*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_FALSE;
625*f4ee7fbaSAndroid Build Coastguard Worker   }
626*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
627*f4ee7fbaSAndroid Build Coastguard Worker }
628*f4ee7fbaSAndroid Build Coastguard Worker 
FileSize(const char * path)629*f4ee7fbaSAndroid Build Coastguard Worker static int64_t FileSize(const char* path) {
630*f4ee7fbaSAndroid Build Coastguard Worker   FILE* f = fopen(path, "rb");
631*f4ee7fbaSAndroid Build Coastguard Worker   int64_t retval;
632*f4ee7fbaSAndroid Build Coastguard Worker   if (f == NULL) {
633*f4ee7fbaSAndroid Build Coastguard Worker     return -1;
634*f4ee7fbaSAndroid Build Coastguard Worker   }
635*f4ee7fbaSAndroid Build Coastguard Worker   if (fseek(f, 0L, SEEK_END) != 0) {
636*f4ee7fbaSAndroid Build Coastguard Worker     fclose(f);
637*f4ee7fbaSAndroid Build Coastguard Worker     return -1;
638*f4ee7fbaSAndroid Build Coastguard Worker   }
639*f4ee7fbaSAndroid Build Coastguard Worker   retval = ftell(f);
640*f4ee7fbaSAndroid Build Coastguard Worker   if (fclose(f) != 0) {
641*f4ee7fbaSAndroid Build Coastguard Worker     return -1;
642*f4ee7fbaSAndroid Build Coastguard Worker   }
643*f4ee7fbaSAndroid Build Coastguard Worker   return retval;
644*f4ee7fbaSAndroid Build Coastguard Worker }
645*f4ee7fbaSAndroid Build Coastguard Worker 
646*f4ee7fbaSAndroid Build Coastguard Worker /* Copy file times and permissions.
647*f4ee7fbaSAndroid Build Coastguard Worker    TODO: this is a "best effort" implementation; honest cross-platform
648*f4ee7fbaSAndroid Build Coastguard Worker    fully featured implementation is way too hacky; add more hacks by request. */
CopyStat(const char * input_path,const char * output_path)649*f4ee7fbaSAndroid Build Coastguard Worker static void CopyStat(const char* input_path, const char* output_path) {
650*f4ee7fbaSAndroid Build Coastguard Worker   struct stat statbuf;
651*f4ee7fbaSAndroid Build Coastguard Worker   struct utimbuf times;
652*f4ee7fbaSAndroid Build Coastguard Worker   int res;
653*f4ee7fbaSAndroid Build Coastguard Worker   if (input_path == 0 || output_path == 0) {
654*f4ee7fbaSAndroid Build Coastguard Worker     return;
655*f4ee7fbaSAndroid Build Coastguard Worker   }
656*f4ee7fbaSAndroid Build Coastguard Worker   if (stat(input_path, &statbuf) != 0) {
657*f4ee7fbaSAndroid Build Coastguard Worker     return;
658*f4ee7fbaSAndroid Build Coastguard Worker   }
659*f4ee7fbaSAndroid Build Coastguard Worker   times.actime = statbuf.st_atime;
660*f4ee7fbaSAndroid Build Coastguard Worker   times.modtime = statbuf.st_mtime;
661*f4ee7fbaSAndroid Build Coastguard Worker   utime(output_path, &times);
662*f4ee7fbaSAndroid Build Coastguard Worker   res = chmod(output_path, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
663*f4ee7fbaSAndroid Build Coastguard Worker   if (res != 0) {
664*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "setting access bits failed for [%s]: %s\n",
665*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(output_path), strerror(errno));
666*f4ee7fbaSAndroid Build Coastguard Worker   }
667*f4ee7fbaSAndroid Build Coastguard Worker   res = chown(output_path, (uid_t)-1, statbuf.st_gid);
668*f4ee7fbaSAndroid Build Coastguard Worker   if (res != 0) {
669*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "setting group failed for [%s]: %s\n",
670*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(output_path), strerror(errno));
671*f4ee7fbaSAndroid Build Coastguard Worker   }
672*f4ee7fbaSAndroid Build Coastguard Worker   res = chown(output_path, statbuf.st_uid, (gid_t)-1);
673*f4ee7fbaSAndroid Build Coastguard Worker   if (res != 0) {
674*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "setting user failed for [%s]: %s\n",
675*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(output_path), strerror(errno));
676*f4ee7fbaSAndroid Build Coastguard Worker   }
677*f4ee7fbaSAndroid Build Coastguard Worker }
678*f4ee7fbaSAndroid Build Coastguard Worker 
NextFile(Context * context)679*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL NextFile(Context* context) {
680*f4ee7fbaSAndroid Build Coastguard Worker   const char* arg;
681*f4ee7fbaSAndroid Build Coastguard Worker   size_t arg_len;
682*f4ee7fbaSAndroid Build Coastguard Worker 
683*f4ee7fbaSAndroid Build Coastguard Worker   /* Iterator points to last used arg; increment to search for the next one. */
684*f4ee7fbaSAndroid Build Coastguard Worker   context->iterator++;
685*f4ee7fbaSAndroid Build Coastguard Worker 
686*f4ee7fbaSAndroid Build Coastguard Worker   context->input_file_length = -1;
687*f4ee7fbaSAndroid Build Coastguard Worker 
688*f4ee7fbaSAndroid Build Coastguard Worker   /* No input path; read from console. */
689*f4ee7fbaSAndroid Build Coastguard Worker   if (context->input_count == 0) {
690*f4ee7fbaSAndroid Build Coastguard Worker     if (context->iterator > 1) return BROTLI_FALSE;
691*f4ee7fbaSAndroid Build Coastguard Worker     context->current_input_path = NULL;
692*f4ee7fbaSAndroid Build Coastguard Worker     /* Either write to the specified path, or to console. */
693*f4ee7fbaSAndroid Build Coastguard Worker     context->current_output_path = context->output_path;
694*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
695*f4ee7fbaSAndroid Build Coastguard Worker   }
696*f4ee7fbaSAndroid Build Coastguard Worker 
697*f4ee7fbaSAndroid Build Coastguard Worker   /* Skip option arguments. */
698*f4ee7fbaSAndroid Build Coastguard Worker   while (context->iterator == context->not_input_indices[context->ignore]) {
699*f4ee7fbaSAndroid Build Coastguard Worker     context->iterator++;
700*f4ee7fbaSAndroid Build Coastguard Worker     context->ignore++;
701*f4ee7fbaSAndroid Build Coastguard Worker   }
702*f4ee7fbaSAndroid Build Coastguard Worker 
703*f4ee7fbaSAndroid Build Coastguard Worker   /* All args are scanned already. */
704*f4ee7fbaSAndroid Build Coastguard Worker   if (context->iterator >= context->argc) return BROTLI_FALSE;
705*f4ee7fbaSAndroid Build Coastguard Worker 
706*f4ee7fbaSAndroid Build Coastguard Worker   /* Iterator now points to the input file name. */
707*f4ee7fbaSAndroid Build Coastguard Worker   arg = context->argv[context->iterator];
708*f4ee7fbaSAndroid Build Coastguard Worker   arg_len = strlen(arg);
709*f4ee7fbaSAndroid Build Coastguard Worker   /* Read from console. */
710*f4ee7fbaSAndroid Build Coastguard Worker   if (arg_len == 1 && arg[0] == '-') {
711*f4ee7fbaSAndroid Build Coastguard Worker     context->current_input_path = NULL;
712*f4ee7fbaSAndroid Build Coastguard Worker     context->current_output_path = context->output_path;
713*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
714*f4ee7fbaSAndroid Build Coastguard Worker   }
715*f4ee7fbaSAndroid Build Coastguard Worker 
716*f4ee7fbaSAndroid Build Coastguard Worker   context->current_input_path = arg;
717*f4ee7fbaSAndroid Build Coastguard Worker   context->input_file_length = FileSize(arg);
718*f4ee7fbaSAndroid Build Coastguard Worker   context->current_output_path = context->output_path;
719*f4ee7fbaSAndroid Build Coastguard Worker 
720*f4ee7fbaSAndroid Build Coastguard Worker   if (context->output_path) return BROTLI_TRUE;
721*f4ee7fbaSAndroid Build Coastguard Worker   if (context->write_to_stdout) return BROTLI_TRUE;
722*f4ee7fbaSAndroid Build Coastguard Worker 
723*f4ee7fbaSAndroid Build Coastguard Worker   strcpy(context->modified_path, arg);
724*f4ee7fbaSAndroid Build Coastguard Worker   context->current_output_path = context->modified_path;
725*f4ee7fbaSAndroid Build Coastguard Worker   /* If output is not specified, input path suffix should match. */
726*f4ee7fbaSAndroid Build Coastguard Worker   if (context->decompress) {
727*f4ee7fbaSAndroid Build Coastguard Worker     size_t suffix_len = strlen(context->suffix);
728*f4ee7fbaSAndroid Build Coastguard Worker     char* name = (char*)FileName(context->modified_path);
729*f4ee7fbaSAndroid Build Coastguard Worker     char* name_suffix;
730*f4ee7fbaSAndroid Build Coastguard Worker     size_t name_len = strlen(name);
731*f4ee7fbaSAndroid Build Coastguard Worker     if (name_len < suffix_len + 1) {
732*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "empty output file name for [%s] input file\n",
733*f4ee7fbaSAndroid Build Coastguard Worker               PrintablePath(arg));
734*f4ee7fbaSAndroid Build Coastguard Worker       context->iterator_error = BROTLI_TRUE;
735*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
736*f4ee7fbaSAndroid Build Coastguard Worker     }
737*f4ee7fbaSAndroid Build Coastguard Worker     name_suffix = name + name_len - suffix_len;
738*f4ee7fbaSAndroid Build Coastguard Worker     if (strcmp(context->suffix, name_suffix) != 0) {
739*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "input file [%s] suffix mismatch\n",
740*f4ee7fbaSAndroid Build Coastguard Worker               PrintablePath(arg));
741*f4ee7fbaSAndroid Build Coastguard Worker       context->iterator_error = BROTLI_TRUE;
742*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
743*f4ee7fbaSAndroid Build Coastguard Worker     }
744*f4ee7fbaSAndroid Build Coastguard Worker     name_suffix[0] = 0;
745*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
746*f4ee7fbaSAndroid Build Coastguard Worker   } else {
747*f4ee7fbaSAndroid Build Coastguard Worker     strcpy(context->modified_path + arg_len, context->suffix);
748*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_TRUE;
749*f4ee7fbaSAndroid Build Coastguard Worker   }
750*f4ee7fbaSAndroid Build Coastguard Worker }
751*f4ee7fbaSAndroid Build Coastguard Worker 
OpenFiles(Context * context)752*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL OpenFiles(Context* context) {
753*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL is_ok = OpenInputFile(context->current_input_path, &context->fin);
754*f4ee7fbaSAndroid Build Coastguard Worker   if (!context->test_integrity && is_ok) {
755*f4ee7fbaSAndroid Build Coastguard Worker     is_ok = OpenOutputFile(
756*f4ee7fbaSAndroid Build Coastguard Worker         context->current_output_path, &context->fout, context->force_overwrite);
757*f4ee7fbaSAndroid Build Coastguard Worker   }
758*f4ee7fbaSAndroid Build Coastguard Worker   return is_ok;
759*f4ee7fbaSAndroid Build Coastguard Worker }
760*f4ee7fbaSAndroid Build Coastguard Worker 
CloseFiles(Context * context,BROTLI_BOOL success)761*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL CloseFiles(Context* context, BROTLI_BOOL success) {
762*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL is_ok = BROTLI_TRUE;
763*f4ee7fbaSAndroid Build Coastguard Worker   if (!context->test_integrity && context->fout) {
764*f4ee7fbaSAndroid Build Coastguard Worker     if (!success && context->current_output_path) {
765*f4ee7fbaSAndroid Build Coastguard Worker       unlink(context->current_output_path);
766*f4ee7fbaSAndroid Build Coastguard Worker     }
767*f4ee7fbaSAndroid Build Coastguard Worker     if (fclose(context->fout) != 0) {
768*f4ee7fbaSAndroid Build Coastguard Worker       if (success) {
769*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "fclose failed [%s]: %s\n",
770*f4ee7fbaSAndroid Build Coastguard Worker                 PrintablePath(context->current_output_path), strerror(errno));
771*f4ee7fbaSAndroid Build Coastguard Worker       }
772*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = BROTLI_FALSE;
773*f4ee7fbaSAndroid Build Coastguard Worker     }
774*f4ee7fbaSAndroid Build Coastguard Worker 
775*f4ee7fbaSAndroid Build Coastguard Worker     /* TOCTOU violation, but otherwise it is impossible to set file times. */
776*f4ee7fbaSAndroid Build Coastguard Worker     if (success && is_ok && context->copy_stat) {
777*f4ee7fbaSAndroid Build Coastguard Worker       CopyStat(context->current_input_path, context->current_output_path);
778*f4ee7fbaSAndroid Build Coastguard Worker     }
779*f4ee7fbaSAndroid Build Coastguard Worker   }
780*f4ee7fbaSAndroid Build Coastguard Worker 
781*f4ee7fbaSAndroid Build Coastguard Worker   if (context->fin) {
782*f4ee7fbaSAndroid Build Coastguard Worker     if (fclose(context->fin) != 0) {
783*f4ee7fbaSAndroid Build Coastguard Worker       if (is_ok) {
784*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "fclose failed [%s]: %s\n",
785*f4ee7fbaSAndroid Build Coastguard Worker                 PrintablePath(context->current_input_path), strerror(errno));
786*f4ee7fbaSAndroid Build Coastguard Worker       }
787*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = BROTLI_FALSE;
788*f4ee7fbaSAndroid Build Coastguard Worker     }
789*f4ee7fbaSAndroid Build Coastguard Worker   }
790*f4ee7fbaSAndroid Build Coastguard Worker   if (success && context->junk_source && context->current_input_path) {
791*f4ee7fbaSAndroid Build Coastguard Worker     unlink(context->current_input_path);
792*f4ee7fbaSAndroid Build Coastguard Worker   }
793*f4ee7fbaSAndroid Build Coastguard Worker 
794*f4ee7fbaSAndroid Build Coastguard Worker   context->fin = NULL;
795*f4ee7fbaSAndroid Build Coastguard Worker   context->fout = NULL;
796*f4ee7fbaSAndroid Build Coastguard Worker 
797*f4ee7fbaSAndroid Build Coastguard Worker   return is_ok;
798*f4ee7fbaSAndroid Build Coastguard Worker }
799*f4ee7fbaSAndroid Build Coastguard Worker 
800*f4ee7fbaSAndroid Build Coastguard Worker static const size_t kFileBufferSize = 1 << 19;
801*f4ee7fbaSAndroid Build Coastguard Worker 
InitializeBuffers(Context * context)802*f4ee7fbaSAndroid Build Coastguard Worker static void InitializeBuffers(Context* context) {
803*f4ee7fbaSAndroid Build Coastguard Worker   context->available_in = 0;
804*f4ee7fbaSAndroid Build Coastguard Worker   context->next_in = NULL;
805*f4ee7fbaSAndroid Build Coastguard Worker   context->available_out = kFileBufferSize;
806*f4ee7fbaSAndroid Build Coastguard Worker   context->next_out = context->output;
807*f4ee7fbaSAndroid Build Coastguard Worker   context->total_in = 0;
808*f4ee7fbaSAndroid Build Coastguard Worker   context->total_out = 0;
809*f4ee7fbaSAndroid Build Coastguard Worker }
810*f4ee7fbaSAndroid Build Coastguard Worker 
811*f4ee7fbaSAndroid Build Coastguard Worker /* This method might give the false-negative result.
812*f4ee7fbaSAndroid Build Coastguard Worker    However, after an empty / incomplete read it should tell the truth. */
HasMoreInput(Context * context)813*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL HasMoreInput(Context* context) {
814*f4ee7fbaSAndroid Build Coastguard Worker   return feof(context->fin) ? BROTLI_FALSE : BROTLI_TRUE;
815*f4ee7fbaSAndroid Build Coastguard Worker }
816*f4ee7fbaSAndroid Build Coastguard Worker 
ProvideInput(Context * context)817*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL ProvideInput(Context* context) {
818*f4ee7fbaSAndroid Build Coastguard Worker   context->available_in =
819*f4ee7fbaSAndroid Build Coastguard Worker       fread(context->input, 1, kFileBufferSize, context->fin);
820*f4ee7fbaSAndroid Build Coastguard Worker   context->total_in += context->available_in;
821*f4ee7fbaSAndroid Build Coastguard Worker   context->next_in = context->input;
822*f4ee7fbaSAndroid Build Coastguard Worker   if (ferror(context->fin)) {
823*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "failed to read input [%s]: %s\n",
824*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(context->current_input_path), strerror(errno));
825*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_FALSE;
826*f4ee7fbaSAndroid Build Coastguard Worker   }
827*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
828*f4ee7fbaSAndroid Build Coastguard Worker }
829*f4ee7fbaSAndroid Build Coastguard Worker 
830*f4ee7fbaSAndroid Build Coastguard Worker /* Internal: should be used only in Provide-/Flush-Output. */
WriteOutput(Context * context)831*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL WriteOutput(Context* context) {
832*f4ee7fbaSAndroid Build Coastguard Worker   size_t out_size = (size_t)(context->next_out - context->output);
833*f4ee7fbaSAndroid Build Coastguard Worker   context->total_out += out_size;
834*f4ee7fbaSAndroid Build Coastguard Worker   if (out_size == 0) return BROTLI_TRUE;
835*f4ee7fbaSAndroid Build Coastguard Worker   if (context->test_integrity) return BROTLI_TRUE;
836*f4ee7fbaSAndroid Build Coastguard Worker 
837*f4ee7fbaSAndroid Build Coastguard Worker   fwrite(context->output, 1, out_size, context->fout);
838*f4ee7fbaSAndroid Build Coastguard Worker   if (ferror(context->fout)) {
839*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "failed to write output [%s]: %s\n",
840*f4ee7fbaSAndroid Build Coastguard Worker             PrintablePath(context->current_output_path), strerror(errno));
841*f4ee7fbaSAndroid Build Coastguard Worker     return BROTLI_FALSE;
842*f4ee7fbaSAndroid Build Coastguard Worker   }
843*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
844*f4ee7fbaSAndroid Build Coastguard Worker }
845*f4ee7fbaSAndroid Build Coastguard Worker 
ProvideOutput(Context * context)846*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL ProvideOutput(Context* context) {
847*f4ee7fbaSAndroid Build Coastguard Worker   if (!WriteOutput(context)) return BROTLI_FALSE;
848*f4ee7fbaSAndroid Build Coastguard Worker   context->available_out = kFileBufferSize;
849*f4ee7fbaSAndroid Build Coastguard Worker   context->next_out = context->output;
850*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
851*f4ee7fbaSAndroid Build Coastguard Worker }
852*f4ee7fbaSAndroid Build Coastguard Worker 
FlushOutput(Context * context)853*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL FlushOutput(Context* context) {
854*f4ee7fbaSAndroid Build Coastguard Worker   if (!WriteOutput(context)) return BROTLI_FALSE;
855*f4ee7fbaSAndroid Build Coastguard Worker   context->available_out = 0;
856*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
857*f4ee7fbaSAndroid Build Coastguard Worker }
858*f4ee7fbaSAndroid Build Coastguard Worker 
PrintBytes(size_t value)859*f4ee7fbaSAndroid Build Coastguard Worker static void PrintBytes(size_t value) {
860*f4ee7fbaSAndroid Build Coastguard Worker   if (value < 1024) {
861*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "%d B", (int)value);
862*f4ee7fbaSAndroid Build Coastguard Worker   } else if (value < 1048576) {
863*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "%0.3f KiB", (double)value / 1024.0);
864*f4ee7fbaSAndroid Build Coastguard Worker   } else if (value < 1073741824) {
865*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "%0.3f MiB", (double)value / 1048576.0);
866*f4ee7fbaSAndroid Build Coastguard Worker   } else {
867*f4ee7fbaSAndroid Build Coastguard Worker     fprintf(stderr, "%0.3f GiB", (double)value / 1073741824.0);
868*f4ee7fbaSAndroid Build Coastguard Worker   }
869*f4ee7fbaSAndroid Build Coastguard Worker }
870*f4ee7fbaSAndroid Build Coastguard Worker 
PrintFileProcessingProgress(Context * context)871*f4ee7fbaSAndroid Build Coastguard Worker static void PrintFileProcessingProgress(Context* context) {
872*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(stderr, "[%s]: ", PrintablePath(context->current_input_path));
873*f4ee7fbaSAndroid Build Coastguard Worker   PrintBytes(context->total_in);
874*f4ee7fbaSAndroid Build Coastguard Worker   fprintf(stderr, " -> ");
875*f4ee7fbaSAndroid Build Coastguard Worker   PrintBytes(context->total_out);
876*f4ee7fbaSAndroid Build Coastguard Worker }
877*f4ee7fbaSAndroid Build Coastguard Worker 
DecompressFile(Context * context,BrotliDecoderState * s)878*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL DecompressFile(Context* context, BrotliDecoderState* s) {
879*f4ee7fbaSAndroid Build Coastguard Worker   BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
880*f4ee7fbaSAndroid Build Coastguard Worker   InitializeBuffers(context);
881*f4ee7fbaSAndroid Build Coastguard Worker   for (;;) {
882*f4ee7fbaSAndroid Build Coastguard Worker     if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
883*f4ee7fbaSAndroid Build Coastguard Worker       if (!HasMoreInput(context)) {
884*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "corrupt input [%s]\n",
885*f4ee7fbaSAndroid Build Coastguard Worker                 PrintablePath(context->current_input_path));
886*f4ee7fbaSAndroid Build Coastguard Worker         return BROTLI_FALSE;
887*f4ee7fbaSAndroid Build Coastguard Worker       }
888*f4ee7fbaSAndroid Build Coastguard Worker       if (!ProvideInput(context)) return BROTLI_FALSE;
889*f4ee7fbaSAndroid Build Coastguard Worker     } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
890*f4ee7fbaSAndroid Build Coastguard Worker       if (!ProvideOutput(context)) return BROTLI_FALSE;
891*f4ee7fbaSAndroid Build Coastguard Worker     } else if (result == BROTLI_DECODER_RESULT_SUCCESS) {
892*f4ee7fbaSAndroid Build Coastguard Worker       if (!FlushOutput(context)) return BROTLI_FALSE;
893*f4ee7fbaSAndroid Build Coastguard Worker       int has_more_input =
894*f4ee7fbaSAndroid Build Coastguard Worker           (context->available_in != 0) || (fgetc(context->fin) != EOF);
895*f4ee7fbaSAndroid Build Coastguard Worker       if (has_more_input) {
896*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "corrupt input [%s]\n",
897*f4ee7fbaSAndroid Build Coastguard Worker                 PrintablePath(context->current_input_path));
898*f4ee7fbaSAndroid Build Coastguard Worker         return BROTLI_FALSE;
899*f4ee7fbaSAndroid Build Coastguard Worker       }
900*f4ee7fbaSAndroid Build Coastguard Worker       if (context->verbosity > 0) {
901*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "Decompressed ");
902*f4ee7fbaSAndroid Build Coastguard Worker         PrintFileProcessingProgress(context);
903*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "\n");
904*f4ee7fbaSAndroid Build Coastguard Worker       }
905*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_TRUE;
906*f4ee7fbaSAndroid Build Coastguard Worker     } else {
907*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "corrupt input [%s]\n",
908*f4ee7fbaSAndroid Build Coastguard Worker               PrintablePath(context->current_input_path));
909*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
910*f4ee7fbaSAndroid Build Coastguard Worker     }
911*f4ee7fbaSAndroid Build Coastguard Worker 
912*f4ee7fbaSAndroid Build Coastguard Worker     result = BrotliDecoderDecompressStream(s, &context->available_in,
913*f4ee7fbaSAndroid Build Coastguard Worker         &context->next_in, &context->available_out, &context->next_out, 0);
914*f4ee7fbaSAndroid Build Coastguard Worker   }
915*f4ee7fbaSAndroid Build Coastguard Worker }
916*f4ee7fbaSAndroid Build Coastguard Worker 
DecompressFiles(Context * context)917*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL DecompressFiles(Context* context) {
918*f4ee7fbaSAndroid Build Coastguard Worker   while (NextFile(context)) {
919*f4ee7fbaSAndroid Build Coastguard Worker     BROTLI_BOOL is_ok = BROTLI_TRUE;
920*f4ee7fbaSAndroid Build Coastguard Worker     BrotliDecoderState* s = BrotliDecoderCreateInstance(NULL, NULL, NULL);
921*f4ee7fbaSAndroid Build Coastguard Worker     if (!s) {
922*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "out of memory\n");
923*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
924*f4ee7fbaSAndroid Build Coastguard Worker     }
925*f4ee7fbaSAndroid Build Coastguard Worker     /* This allows decoding "large-window" streams. Though it creates
926*f4ee7fbaSAndroid Build Coastguard Worker        fragmentation (new builds decode streams that old builds don't),
927*f4ee7fbaSAndroid Build Coastguard Worker        it is better from used experience perspective. */
928*f4ee7fbaSAndroid Build Coastguard Worker     BrotliDecoderSetParameter(s, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1u);
929*f4ee7fbaSAndroid Build Coastguard Worker     is_ok = OpenFiles(context);
930*f4ee7fbaSAndroid Build Coastguard Worker     if (is_ok && !context->current_input_path &&
931*f4ee7fbaSAndroid Build Coastguard Worker         !context->force_overwrite && isatty(STDIN_FILENO)) {
932*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "Use -h help. Use -f to force input from a terminal.\n");
933*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = BROTLI_FALSE;
934*f4ee7fbaSAndroid Build Coastguard Worker     }
935*f4ee7fbaSAndroid Build Coastguard Worker     if (is_ok) is_ok = DecompressFile(context, s);
936*f4ee7fbaSAndroid Build Coastguard Worker     BrotliDecoderDestroyInstance(s);
937*f4ee7fbaSAndroid Build Coastguard Worker     if (!CloseFiles(context, is_ok)) is_ok = BROTLI_FALSE;
938*f4ee7fbaSAndroid Build Coastguard Worker     if (!is_ok) return BROTLI_FALSE;
939*f4ee7fbaSAndroid Build Coastguard Worker   }
940*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
941*f4ee7fbaSAndroid Build Coastguard Worker }
942*f4ee7fbaSAndroid Build Coastguard Worker 
CompressFile(Context * context,BrotliEncoderState * s)943*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL CompressFile(Context* context, BrotliEncoderState* s) {
944*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL is_eof = BROTLI_FALSE;
945*f4ee7fbaSAndroid Build Coastguard Worker   InitializeBuffers(context);
946*f4ee7fbaSAndroid Build Coastguard Worker   for (;;) {
947*f4ee7fbaSAndroid Build Coastguard Worker     if (context->available_in == 0 && !is_eof) {
948*f4ee7fbaSAndroid Build Coastguard Worker       if (!ProvideInput(context)) return BROTLI_FALSE;
949*f4ee7fbaSAndroid Build Coastguard Worker       is_eof = !HasMoreInput(context);
950*f4ee7fbaSAndroid Build Coastguard Worker     }
951*f4ee7fbaSAndroid Build Coastguard Worker 
952*f4ee7fbaSAndroid Build Coastguard Worker     if (!BrotliEncoderCompressStream(s,
953*f4ee7fbaSAndroid Build Coastguard Worker         is_eof ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS,
954*f4ee7fbaSAndroid Build Coastguard Worker         &context->available_in, &context->next_in,
955*f4ee7fbaSAndroid Build Coastguard Worker         &context->available_out, &context->next_out, NULL)) {
956*f4ee7fbaSAndroid Build Coastguard Worker       /* Should detect OOM? */
957*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "failed to compress data [%s]\n",
958*f4ee7fbaSAndroid Build Coastguard Worker               PrintablePath(context->current_input_path));
959*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
960*f4ee7fbaSAndroid Build Coastguard Worker     }
961*f4ee7fbaSAndroid Build Coastguard Worker 
962*f4ee7fbaSAndroid Build Coastguard Worker     if (context->available_out == 0) {
963*f4ee7fbaSAndroid Build Coastguard Worker       if (!ProvideOutput(context)) return BROTLI_FALSE;
964*f4ee7fbaSAndroid Build Coastguard Worker     }
965*f4ee7fbaSAndroid Build Coastguard Worker 
966*f4ee7fbaSAndroid Build Coastguard Worker     if (BrotliEncoderIsFinished(s)) {
967*f4ee7fbaSAndroid Build Coastguard Worker       if (!FlushOutput(context)) return BROTLI_FALSE;
968*f4ee7fbaSAndroid Build Coastguard Worker       if (context->verbosity > 0) {
969*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "Compressed ");
970*f4ee7fbaSAndroid Build Coastguard Worker         PrintFileProcessingProgress(context);
971*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "\n");
972*f4ee7fbaSAndroid Build Coastguard Worker       }
973*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_TRUE;
974*f4ee7fbaSAndroid Build Coastguard Worker     }
975*f4ee7fbaSAndroid Build Coastguard Worker   }
976*f4ee7fbaSAndroid Build Coastguard Worker }
977*f4ee7fbaSAndroid Build Coastguard Worker 
CompressFiles(Context * context)978*f4ee7fbaSAndroid Build Coastguard Worker static BROTLI_BOOL CompressFiles(Context* context) {
979*f4ee7fbaSAndroid Build Coastguard Worker   while (NextFile(context)) {
980*f4ee7fbaSAndroid Build Coastguard Worker     BROTLI_BOOL is_ok = BROTLI_TRUE;
981*f4ee7fbaSAndroid Build Coastguard Worker     BrotliEncoderState* s = BrotliEncoderCreateInstance(NULL, NULL, NULL);
982*f4ee7fbaSAndroid Build Coastguard Worker     if (!s) {
983*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "out of memory\n");
984*f4ee7fbaSAndroid Build Coastguard Worker       return BROTLI_FALSE;
985*f4ee7fbaSAndroid Build Coastguard Worker     }
986*f4ee7fbaSAndroid Build Coastguard Worker     BrotliEncoderSetParameter(s,
987*f4ee7fbaSAndroid Build Coastguard Worker         BROTLI_PARAM_QUALITY, (uint32_t)context->quality);
988*f4ee7fbaSAndroid Build Coastguard Worker     if (context->lgwin > 0) {
989*f4ee7fbaSAndroid Build Coastguard Worker       /* Specified by user. */
990*f4ee7fbaSAndroid Build Coastguard Worker       /* Do not enable "large-window" extension, if not required. */
991*f4ee7fbaSAndroid Build Coastguard Worker       if (context->lgwin > BROTLI_MAX_WINDOW_BITS) {
992*f4ee7fbaSAndroid Build Coastguard Worker         BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, 1u);
993*f4ee7fbaSAndroid Build Coastguard Worker       }
994*f4ee7fbaSAndroid Build Coastguard Worker       BrotliEncoderSetParameter(s,
995*f4ee7fbaSAndroid Build Coastguard Worker           BROTLI_PARAM_LGWIN, (uint32_t)context->lgwin);
996*f4ee7fbaSAndroid Build Coastguard Worker     } else {
997*f4ee7fbaSAndroid Build Coastguard Worker       /* 0, or not specified by user; could be chosen by compressor. */
998*f4ee7fbaSAndroid Build Coastguard Worker       uint32_t lgwin = DEFAULT_LGWIN;
999*f4ee7fbaSAndroid Build Coastguard Worker       /* Use file size to limit lgwin. */
1000*f4ee7fbaSAndroid Build Coastguard Worker       if (context->input_file_length >= 0) {
1001*f4ee7fbaSAndroid Build Coastguard Worker         lgwin = BROTLI_MIN_WINDOW_BITS;
1002*f4ee7fbaSAndroid Build Coastguard Worker         while (BROTLI_MAX_BACKWARD_LIMIT(lgwin) <
1003*f4ee7fbaSAndroid Build Coastguard Worker                (uint64_t)context->input_file_length) {
1004*f4ee7fbaSAndroid Build Coastguard Worker           lgwin++;
1005*f4ee7fbaSAndroid Build Coastguard Worker           if (lgwin == BROTLI_MAX_WINDOW_BITS) break;
1006*f4ee7fbaSAndroid Build Coastguard Worker         }
1007*f4ee7fbaSAndroid Build Coastguard Worker       }
1008*f4ee7fbaSAndroid Build Coastguard Worker       BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, lgwin);
1009*f4ee7fbaSAndroid Build Coastguard Worker     }
1010*f4ee7fbaSAndroid Build Coastguard Worker     if (context->input_file_length > 0) {
1011*f4ee7fbaSAndroid Build Coastguard Worker       uint32_t size_hint = context->input_file_length < (1 << 30) ?
1012*f4ee7fbaSAndroid Build Coastguard Worker           (uint32_t)context->input_file_length : (1u << 30);
1013*f4ee7fbaSAndroid Build Coastguard Worker       BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, size_hint);
1014*f4ee7fbaSAndroid Build Coastguard Worker     }
1015*f4ee7fbaSAndroid Build Coastguard Worker     is_ok = OpenFiles(context);
1016*f4ee7fbaSAndroid Build Coastguard Worker     if (is_ok && !context->current_output_path &&
1017*f4ee7fbaSAndroid Build Coastguard Worker         !context->force_overwrite && isatty(STDOUT_FILENO)) {
1018*f4ee7fbaSAndroid Build Coastguard Worker       fprintf(stderr, "Use -h help. Use -f to force output to a terminal.\n");
1019*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = BROTLI_FALSE;
1020*f4ee7fbaSAndroid Build Coastguard Worker     }
1021*f4ee7fbaSAndroid Build Coastguard Worker     if (is_ok) is_ok = CompressFile(context, s);
1022*f4ee7fbaSAndroid Build Coastguard Worker     BrotliEncoderDestroyInstance(s);
1023*f4ee7fbaSAndroid Build Coastguard Worker     if (!CloseFiles(context, is_ok)) is_ok = BROTLI_FALSE;
1024*f4ee7fbaSAndroid Build Coastguard Worker     if (!is_ok) return BROTLI_FALSE;
1025*f4ee7fbaSAndroid Build Coastguard Worker   }
1026*f4ee7fbaSAndroid Build Coastguard Worker   return BROTLI_TRUE;
1027*f4ee7fbaSAndroid Build Coastguard Worker }
1028*f4ee7fbaSAndroid Build Coastguard Worker 
main(int argc,char ** argv)1029*f4ee7fbaSAndroid Build Coastguard Worker int main(int argc, char** argv) {
1030*f4ee7fbaSAndroid Build Coastguard Worker   Command command;
1031*f4ee7fbaSAndroid Build Coastguard Worker   Context context;
1032*f4ee7fbaSAndroid Build Coastguard Worker   BROTLI_BOOL is_ok = BROTLI_TRUE;
1033*f4ee7fbaSAndroid Build Coastguard Worker   int i;
1034*f4ee7fbaSAndroid Build Coastguard Worker 
1035*f4ee7fbaSAndroid Build Coastguard Worker   context.quality = 11;
1036*f4ee7fbaSAndroid Build Coastguard Worker   context.lgwin = -1;
1037*f4ee7fbaSAndroid Build Coastguard Worker   context.verbosity = 0;
1038*f4ee7fbaSAndroid Build Coastguard Worker   context.force_overwrite = BROTLI_FALSE;
1039*f4ee7fbaSAndroid Build Coastguard Worker   context.junk_source = BROTLI_FALSE;
1040*f4ee7fbaSAndroid Build Coastguard Worker   context.copy_stat = BROTLI_TRUE;
1041*f4ee7fbaSAndroid Build Coastguard Worker   context.test_integrity = BROTLI_FALSE;
1042*f4ee7fbaSAndroid Build Coastguard Worker   context.write_to_stdout = BROTLI_FALSE;
1043*f4ee7fbaSAndroid Build Coastguard Worker   context.decompress = BROTLI_FALSE;
1044*f4ee7fbaSAndroid Build Coastguard Worker   context.large_window = BROTLI_FALSE;
1045*f4ee7fbaSAndroid Build Coastguard Worker   context.output_path = NULL;
1046*f4ee7fbaSAndroid Build Coastguard Worker   context.suffix = DEFAULT_SUFFIX;
1047*f4ee7fbaSAndroid Build Coastguard Worker   for (i = 0; i < MAX_OPTIONS; ++i) context.not_input_indices[i] = 0;
1048*f4ee7fbaSAndroid Build Coastguard Worker   context.longest_path_len = 1;
1049*f4ee7fbaSAndroid Build Coastguard Worker   context.input_count = 0;
1050*f4ee7fbaSAndroid Build Coastguard Worker 
1051*f4ee7fbaSAndroid Build Coastguard Worker   context.argc = argc;
1052*f4ee7fbaSAndroid Build Coastguard Worker   context.argv = argv;
1053*f4ee7fbaSAndroid Build Coastguard Worker   context.modified_path = NULL;
1054*f4ee7fbaSAndroid Build Coastguard Worker   context.iterator = 0;
1055*f4ee7fbaSAndroid Build Coastguard Worker   context.ignore = 0;
1056*f4ee7fbaSAndroid Build Coastguard Worker   context.iterator_error = BROTLI_FALSE;
1057*f4ee7fbaSAndroid Build Coastguard Worker   context.buffer = NULL;
1058*f4ee7fbaSAndroid Build Coastguard Worker   context.current_input_path = NULL;
1059*f4ee7fbaSAndroid Build Coastguard Worker   context.current_output_path = NULL;
1060*f4ee7fbaSAndroid Build Coastguard Worker   context.fin = NULL;
1061*f4ee7fbaSAndroid Build Coastguard Worker   context.fout = NULL;
1062*f4ee7fbaSAndroid Build Coastguard Worker 
1063*f4ee7fbaSAndroid Build Coastguard Worker   command = ParseParams(&context);
1064*f4ee7fbaSAndroid Build Coastguard Worker 
1065*f4ee7fbaSAndroid Build Coastguard Worker   if (command == COMMAND_COMPRESS || command == COMMAND_DECOMPRESS ||
1066*f4ee7fbaSAndroid Build Coastguard Worker       command == COMMAND_TEST_INTEGRITY) {
1067*f4ee7fbaSAndroid Build Coastguard Worker     if (is_ok) {
1068*f4ee7fbaSAndroid Build Coastguard Worker       size_t modified_path_len =
1069*f4ee7fbaSAndroid Build Coastguard Worker           context.longest_path_len + strlen(context.suffix) + 1;
1070*f4ee7fbaSAndroid Build Coastguard Worker       context.modified_path = (char*)malloc(modified_path_len);
1071*f4ee7fbaSAndroid Build Coastguard Worker       context.buffer = (uint8_t*)malloc(kFileBufferSize * 2);
1072*f4ee7fbaSAndroid Build Coastguard Worker       if (!context.modified_path || !context.buffer) {
1073*f4ee7fbaSAndroid Build Coastguard Worker         fprintf(stderr, "out of memory\n");
1074*f4ee7fbaSAndroid Build Coastguard Worker         is_ok = BROTLI_FALSE;
1075*f4ee7fbaSAndroid Build Coastguard Worker       } else {
1076*f4ee7fbaSAndroid Build Coastguard Worker         context.input = context.buffer;
1077*f4ee7fbaSAndroid Build Coastguard Worker         context.output = context.buffer + kFileBufferSize;
1078*f4ee7fbaSAndroid Build Coastguard Worker       }
1079*f4ee7fbaSAndroid Build Coastguard Worker     }
1080*f4ee7fbaSAndroid Build Coastguard Worker   }
1081*f4ee7fbaSAndroid Build Coastguard Worker 
1082*f4ee7fbaSAndroid Build Coastguard Worker   if (!is_ok) command = COMMAND_NOOP;
1083*f4ee7fbaSAndroid Build Coastguard Worker 
1084*f4ee7fbaSAndroid Build Coastguard Worker   switch (command) {
1085*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_NOOP:
1086*f4ee7fbaSAndroid Build Coastguard Worker       break;
1087*f4ee7fbaSAndroid Build Coastguard Worker 
1088*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_VERSION:
1089*f4ee7fbaSAndroid Build Coastguard Worker       PrintVersion();
1090*f4ee7fbaSAndroid Build Coastguard Worker       break;
1091*f4ee7fbaSAndroid Build Coastguard Worker 
1092*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_COMPRESS:
1093*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = CompressFiles(&context);
1094*f4ee7fbaSAndroid Build Coastguard Worker       break;
1095*f4ee7fbaSAndroid Build Coastguard Worker 
1096*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_DECOMPRESS:
1097*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_TEST_INTEGRITY:
1098*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = DecompressFiles(&context);
1099*f4ee7fbaSAndroid Build Coastguard Worker       break;
1100*f4ee7fbaSAndroid Build Coastguard Worker 
1101*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_HELP:
1102*f4ee7fbaSAndroid Build Coastguard Worker     case COMMAND_INVALID:
1103*f4ee7fbaSAndroid Build Coastguard Worker     default:
1104*f4ee7fbaSAndroid Build Coastguard Worker       is_ok = (command == COMMAND_HELP);
1105*f4ee7fbaSAndroid Build Coastguard Worker       PrintHelp(FileName(argv[0]), is_ok);
1106*f4ee7fbaSAndroid Build Coastguard Worker       break;
1107*f4ee7fbaSAndroid Build Coastguard Worker   }
1108*f4ee7fbaSAndroid Build Coastguard Worker 
1109*f4ee7fbaSAndroid Build Coastguard Worker   if (context.iterator_error) is_ok = BROTLI_FALSE;
1110*f4ee7fbaSAndroid Build Coastguard Worker 
1111*f4ee7fbaSAndroid Build Coastguard Worker   free(context.modified_path);
1112*f4ee7fbaSAndroid Build Coastguard Worker   free(context.buffer);
1113*f4ee7fbaSAndroid Build Coastguard Worker 
1114*f4ee7fbaSAndroid Build Coastguard Worker   if (!is_ok) exit(1);
1115*f4ee7fbaSAndroid Build Coastguard Worker   return 0;
1116*f4ee7fbaSAndroid Build Coastguard Worker }
1117