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