1*13d37d77SDavid du Colombier /*
2*13d37d77SDavid du Colombier * Clzip - LZMA lossless data compressor
3*13d37d77SDavid du Colombier * Copyright (C) 2010-2017 Antonio Diaz Diaz.
4*13d37d77SDavid du Colombier *
5*13d37d77SDavid du Colombier * This program is free software: you can redistribute it and/or modify
6*13d37d77SDavid du Colombier * it under the terms of the GNU General Public License as published by
7*13d37d77SDavid du Colombier * the Free Software Foundation, either version 2 of the License, or
8*13d37d77SDavid du Colombier * (at your option) any later version.
9*13d37d77SDavid du Colombier *
10*13d37d77SDavid du Colombier * This program is distributed in the hope that it will be useful,
11*13d37d77SDavid du Colombier * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*13d37d77SDavid du Colombier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*13d37d77SDavid du Colombier * GNU General Public License for more details.
14*13d37d77SDavid du Colombier *
15*13d37d77SDavid du Colombier * You should have received a copy of the GNU General Public License
16*13d37d77SDavid du Colombier * along with this program. If not, see <http://www.gnu.org/licenses/>.
17*13d37d77SDavid du Colombier */
18*13d37d77SDavid du Colombier /*
19*13d37d77SDavid du Colombier * Exit status: 0 for a normal exit, 1 for environmental problems
20*13d37d77SDavid du Colombier * (file not found, invalid flags, I/O errors, etc), 2 to indicate a
21*13d37d77SDavid du Colombier * corrupt or invalid input file, 3 for an internal consistency error
22*13d37d77SDavid du Colombier * (eg, bug) which caused lzip to panic.
23*13d37d77SDavid du Colombier */
24*13d37d77SDavid du Colombier
25*13d37d77SDavid du Colombier #define _DEFINE_INLINES
26*13d37d77SDavid du Colombier #include "lzip.h"
27*13d37d77SDavid du Colombier #include "decoder.h"
28*13d37d77SDavid du Colombier #include "encoder_base.h"
29*13d37d77SDavid du Colombier #include "encoder.h"
30*13d37d77SDavid du Colombier #include "fast_encoder.h"
31*13d37d77SDavid du Colombier
32*13d37d77SDavid du Colombier int verbosity = 0;
33*13d37d77SDavid du Colombier
34*13d37d77SDavid du Colombier char *argv0 = "lzip";
35*13d37d77SDavid du Colombier
36*13d37d77SDavid du Colombier struct {
37*13d37d77SDavid du Colombier char * from;
38*13d37d77SDavid du Colombier char * to;
39*13d37d77SDavid du Colombier } known_extensions[] = {
40*13d37d77SDavid du Colombier { ".lz", "" },
41*13d37d77SDavid du Colombier { ".tlz", ".tar" },
42*13d37d77SDavid du Colombier { 0, 0 }
43*13d37d77SDavid du Colombier };
44*13d37d77SDavid du Colombier
45*13d37d77SDavid du Colombier typedef struct Lzma_options Lzma_options;
46*13d37d77SDavid du Colombier struct Lzma_options {
47*13d37d77SDavid du Colombier int dict_size; /* 4 KiB .. 512 MiB */
48*13d37d77SDavid du Colombier int match_len_limit; /* 5 .. 273 */
49*13d37d77SDavid du Colombier };
50*13d37d77SDavid du Colombier
51*13d37d77SDavid du Colombier enum Mode { m_compress, m_decompress, };
52*13d37d77SDavid du Colombier
53*13d37d77SDavid du Colombier char *output_filename = nil;
54*13d37d77SDavid du Colombier int outfd = -1;
55*13d37d77SDavid du Colombier bool delete_output_on_interrupt = false;
56*13d37d77SDavid du Colombier
57*13d37d77SDavid du Colombier static void
usage(void)58*13d37d77SDavid du Colombier usage(void)
59*13d37d77SDavid du Colombier {
60*13d37d77SDavid du Colombier fprintf(stderr, "Usage: %s [-[0-9]cdv] [file...]\n", argv0);
61*13d37d77SDavid du Colombier exit(2);
62*13d37d77SDavid du Colombier }
63*13d37d77SDavid du Colombier
64*13d37d77SDavid du Colombier char *
bad_version(unsigned version)65*13d37d77SDavid du Colombier bad_version(unsigned version)
66*13d37d77SDavid du Colombier {
67*13d37d77SDavid du Colombier static char buf[80];
68*13d37d77SDavid du Colombier
69*13d37d77SDavid du Colombier snprintf(buf, sizeof buf, "Version %ud member format not supported.",
70*13d37d77SDavid du Colombier version);
71*13d37d77SDavid du Colombier return buf;
72*13d37d77SDavid du Colombier }
73*13d37d77SDavid du Colombier
74*13d37d77SDavid du Colombier char *
format_ds(unsigned dict_size)75*13d37d77SDavid du Colombier format_ds(unsigned dict_size)
76*13d37d77SDavid du Colombier {
77*13d37d77SDavid du Colombier enum { bufsize = 16, factor = 1024 };
78*13d37d77SDavid du Colombier char *prefix[8] = { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
79*13d37d77SDavid du Colombier char *p = "";
80*13d37d77SDavid du Colombier char *np = " ";
81*13d37d77SDavid du Colombier unsigned num = dict_size, i;
82*13d37d77SDavid du Colombier bool exact = (num % factor == 0);
83*13d37d77SDavid du Colombier static char buf[bufsize];
84*13d37d77SDavid du Colombier
85*13d37d77SDavid du Colombier for (i = 0; i < 8 && (num > 9999 || (exact && num >= factor)); ++i) {
86*13d37d77SDavid du Colombier num /= factor;
87*13d37d77SDavid du Colombier if (num % factor != 0)
88*13d37d77SDavid du Colombier exact = false;
89*13d37d77SDavid du Colombier p = prefix[i];
90*13d37d77SDavid du Colombier np = "";
91*13d37d77SDavid du Colombier }
92*13d37d77SDavid du Colombier snprintf( buf, bufsize, "%s%4ud %sB", np, num, p );
93*13d37d77SDavid du Colombier return buf;
94*13d37d77SDavid du Colombier }
95*13d37d77SDavid du Colombier
96*13d37d77SDavid du Colombier static void
show_header(unsigned dict_size)97*13d37d77SDavid du Colombier show_header(unsigned dict_size)
98*13d37d77SDavid du Colombier {
99*13d37d77SDavid du Colombier if (verbosity >= 3)
100*13d37d77SDavid du Colombier fprintf(stderr, "dictionary %s. ", format_ds( dict_size) );
101*13d37d77SDavid du Colombier }
102*13d37d77SDavid du Colombier
103*13d37d77SDavid du Colombier static uvlong
getnum(char * ptr,uvlong llimit,uvlong ulimit)104*13d37d77SDavid du Colombier getnum(char *ptr, uvlong llimit, uvlong ulimit)
105*13d37d77SDavid du Colombier {
106*13d37d77SDavid du Colombier int bad;
107*13d37d77SDavid du Colombier uvlong result;
108*13d37d77SDavid du Colombier char *tail;
109*13d37d77SDavid du Colombier
110*13d37d77SDavid du Colombier bad = 0;
111*13d37d77SDavid du Colombier result = strtoull(ptr, &tail, 0);
112*13d37d77SDavid du Colombier if (tail == ptr) {
113*13d37d77SDavid du Colombier show_error( "Bad or missing numerical argument.", 0, true );
114*13d37d77SDavid du Colombier exit(1);
115*13d37d77SDavid du Colombier }
116*13d37d77SDavid du Colombier
117*13d37d77SDavid du Colombier if (!errno && tail[0]) {
118*13d37d77SDavid du Colombier unsigned factor = (tail[1] == 'i') ? 1024 : 1000;
119*13d37d77SDavid du Colombier int i, exponent = 0; /* 0 = bad multiplier */
120*13d37d77SDavid du Colombier
121*13d37d77SDavid du Colombier switch (tail[0]) {
122*13d37d77SDavid du Colombier case 'Y':
123*13d37d77SDavid du Colombier exponent = 8;
124*13d37d77SDavid du Colombier break;
125*13d37d77SDavid du Colombier case 'Z':
126*13d37d77SDavid du Colombier exponent = 7;
127*13d37d77SDavid du Colombier break;
128*13d37d77SDavid du Colombier case 'E':
129*13d37d77SDavid du Colombier exponent = 6;
130*13d37d77SDavid du Colombier break;
131*13d37d77SDavid du Colombier case 'P':
132*13d37d77SDavid du Colombier exponent = 5;
133*13d37d77SDavid du Colombier break;
134*13d37d77SDavid du Colombier case 'T':
135*13d37d77SDavid du Colombier exponent = 4;
136*13d37d77SDavid du Colombier break;
137*13d37d77SDavid du Colombier case 'G':
138*13d37d77SDavid du Colombier exponent = 3;
139*13d37d77SDavid du Colombier break;
140*13d37d77SDavid du Colombier case 'M':
141*13d37d77SDavid du Colombier exponent = 2;
142*13d37d77SDavid du Colombier break;
143*13d37d77SDavid du Colombier case 'K':
144*13d37d77SDavid du Colombier if (factor == 1024)
145*13d37d77SDavid du Colombier exponent = 1;
146*13d37d77SDavid du Colombier break;
147*13d37d77SDavid du Colombier case 'k':
148*13d37d77SDavid du Colombier if (factor == 1000)
149*13d37d77SDavid du Colombier exponent = 1;
150*13d37d77SDavid du Colombier break;
151*13d37d77SDavid du Colombier }
152*13d37d77SDavid du Colombier if (exponent <= 0) {
153*13d37d77SDavid du Colombier show_error( "Bad multiplier in numerical argument.", 0, true );
154*13d37d77SDavid du Colombier exit(1);
155*13d37d77SDavid du Colombier }
156*13d37d77SDavid du Colombier for (i = 0; i < exponent; ++i) {
157*13d37d77SDavid du Colombier if (ulimit / factor >= result)
158*13d37d77SDavid du Colombier result *= factor;
159*13d37d77SDavid du Colombier else {
160*13d37d77SDavid du Colombier bad++;
161*13d37d77SDavid du Colombier break;
162*13d37d77SDavid du Colombier }
163*13d37d77SDavid du Colombier }
164*13d37d77SDavid du Colombier }
165*13d37d77SDavid du Colombier if (bad || result < llimit || result > ulimit) {
166*13d37d77SDavid du Colombier show_error( "Numerical argument out of limits.", 0, false );
167*13d37d77SDavid du Colombier exit(1);
168*13d37d77SDavid du Colombier }
169*13d37d77SDavid du Colombier return result;
170*13d37d77SDavid du Colombier }
171*13d37d77SDavid du Colombier
172*13d37d77SDavid du Colombier static int
get_dict_size(char * arg)173*13d37d77SDavid du Colombier get_dict_size(char *arg)
174*13d37d77SDavid du Colombier {
175*13d37d77SDavid du Colombier char *tail;
176*13d37d77SDavid du Colombier long bits = strtol(arg, &tail, 0);
177*13d37d77SDavid du Colombier
178*13d37d77SDavid du Colombier if (bits >= min_dict_bits &&
179*13d37d77SDavid du Colombier bits <= max_dict_bits && *tail == 0)
180*13d37d77SDavid du Colombier return (1 << bits);
181*13d37d77SDavid du Colombier return getnum(arg, min_dict_size, max_dict_size);
182*13d37d77SDavid du Colombier }
183*13d37d77SDavid du Colombier
184*13d37d77SDavid du Colombier void
set_mode(enum Mode * program_modep,enum Mode new_mode)185*13d37d77SDavid du Colombier set_mode(enum Mode *program_modep, enum Mode new_mode)
186*13d37d77SDavid du Colombier {
187*13d37d77SDavid du Colombier if (*program_modep != m_compress && *program_modep != new_mode) {
188*13d37d77SDavid du Colombier show_error( "Only one operation can be specified.", 0, true );
189*13d37d77SDavid du Colombier exit(1);
190*13d37d77SDavid du Colombier }
191*13d37d77SDavid du Colombier *program_modep = new_mode;
192*13d37d77SDavid du Colombier }
193*13d37d77SDavid du Colombier
194*13d37d77SDavid du Colombier static int
extension_index(char * name)195*13d37d77SDavid du Colombier extension_index(char *name)
196*13d37d77SDavid du Colombier {
197*13d37d77SDavid du Colombier int eindex;
198*13d37d77SDavid du Colombier
199*13d37d77SDavid du Colombier for (eindex = 0; known_extensions[eindex].from; ++eindex) {
200*13d37d77SDavid du Colombier char * ext = known_extensions[eindex].from;
201*13d37d77SDavid du Colombier unsigned name_len = strlen(name);
202*13d37d77SDavid du Colombier unsigned ext_len = strlen(ext);
203*13d37d77SDavid du Colombier
204*13d37d77SDavid du Colombier if (name_len > ext_len &&
205*13d37d77SDavid du Colombier strncmp(name + name_len - ext_len, ext, ext_len) == 0)
206*13d37d77SDavid du Colombier return eindex;
207*13d37d77SDavid du Colombier }
208*13d37d77SDavid du Colombier return - 1;
209*13d37d77SDavid du Colombier }
210*13d37d77SDavid du Colombier
211*13d37d77SDavid du Colombier int
open_instream(char * name,Dir *,bool,bool)212*13d37d77SDavid du Colombier open_instream(char *name, Dir *, bool, bool)
213*13d37d77SDavid du Colombier {
214*13d37d77SDavid du Colombier int infd = open(name, OREAD);
215*13d37d77SDavid du Colombier
216*13d37d77SDavid du Colombier if (infd < 0)
217*13d37d77SDavid du Colombier show_file_error( name, "Can't open input file", errno );
218*13d37d77SDavid du Colombier return infd;
219*13d37d77SDavid du Colombier }
220*13d37d77SDavid du Colombier
221*13d37d77SDavid du Colombier static int
open_instream2(char * name,Dir * in_statsp,enum Mode program_mode,int eindex,bool recompress,bool to_stdout)222*13d37d77SDavid du Colombier open_instream2(char *name, Dir *in_statsp, enum Mode program_mode,
223*13d37d77SDavid du Colombier int eindex, bool recompress, bool to_stdout)
224*13d37d77SDavid du Colombier {
225*13d37d77SDavid du Colombier bool no_ofile = to_stdout;
226*13d37d77SDavid du Colombier
227*13d37d77SDavid du Colombier if (program_mode == m_compress && !recompress && eindex >= 0) {
228*13d37d77SDavid du Colombier if (verbosity >= 0)
229*13d37d77SDavid du Colombier fprintf( stderr, "%s: Input file '%s' already has '%s' suffix.\n",
230*13d37d77SDavid du Colombier argv0, name, known_extensions[eindex].from);
231*13d37d77SDavid du Colombier return - 1;
232*13d37d77SDavid du Colombier }
233*13d37d77SDavid du Colombier return open_instream(name, in_statsp, no_ofile, false);
234*13d37d77SDavid du Colombier }
235*13d37d77SDavid du Colombier
236*13d37d77SDavid du Colombier /* assure at least a minimum size for buffer 'buf' */
237*13d37d77SDavid du Colombier void *
resize_buffer(void * buf,unsigned min_size)238*13d37d77SDavid du Colombier resize_buffer(void *buf, unsigned min_size)
239*13d37d77SDavid du Colombier {
240*13d37d77SDavid du Colombier buf = realloc(buf, min_size);
241*13d37d77SDavid du Colombier if (!buf) {
242*13d37d77SDavid du Colombier show_error("Not enough memory.", 0, false);
243*13d37d77SDavid du Colombier cleanup_and_fail(1);
244*13d37d77SDavid du Colombier }
245*13d37d77SDavid du Colombier return buf;
246*13d37d77SDavid du Colombier }
247*13d37d77SDavid du Colombier
248*13d37d77SDavid du Colombier static void
set_c_outname(char * name,bool multifile)249*13d37d77SDavid du Colombier set_c_outname(char *name, bool multifile)
250*13d37d77SDavid du Colombier {
251*13d37d77SDavid du Colombier output_filename = resize_buffer(output_filename, strlen(name) + 5 +
252*13d37d77SDavid du Colombier strlen(known_extensions[0].from) + 1);
253*13d37d77SDavid du Colombier strcpy(output_filename, name);
254*13d37d77SDavid du Colombier if (multifile)
255*13d37d77SDavid du Colombier strcat( output_filename, "00001" );
256*13d37d77SDavid du Colombier strcat(output_filename, known_extensions[0].from);
257*13d37d77SDavid du Colombier }
258*13d37d77SDavid du Colombier
259*13d37d77SDavid du Colombier static void
set_d_outname(char * name,int eindex)260*13d37d77SDavid du Colombier set_d_outname(char *name, int eindex)
261*13d37d77SDavid du Colombier {
262*13d37d77SDavid du Colombier unsigned name_len = strlen(name);
263*13d37d77SDavid du Colombier if (eindex >= 0) {
264*13d37d77SDavid du Colombier char * from = known_extensions[eindex].from;
265*13d37d77SDavid du Colombier unsigned from_len = strlen(from);
266*13d37d77SDavid du Colombier
267*13d37d77SDavid du Colombier if (name_len > from_len) {
268*13d37d77SDavid du Colombier output_filename = resize_buffer(output_filename, name_len +
269*13d37d77SDavid du Colombier strlen(known_extensions[eindex].to) + 1);
270*13d37d77SDavid du Colombier strcpy(output_filename, name);
271*13d37d77SDavid du Colombier strcpy(output_filename + name_len - from_len, known_extensions[eindex].to);
272*13d37d77SDavid du Colombier return;
273*13d37d77SDavid du Colombier }
274*13d37d77SDavid du Colombier }
275*13d37d77SDavid du Colombier output_filename = resize_buffer(output_filename, name_len + 4 + 1);
276*13d37d77SDavid du Colombier strcpy(output_filename, name);
277*13d37d77SDavid du Colombier strcat(output_filename, ".out");
278*13d37d77SDavid du Colombier if (verbosity >= 1)
279*13d37d77SDavid du Colombier fprintf( stderr, "%s: Can't guess original name for '%s' -- using '%s'\n",
280*13d37d77SDavid du Colombier argv0, name, output_filename);
281*13d37d77SDavid du Colombier }
282*13d37d77SDavid du Colombier
283*13d37d77SDavid du Colombier static bool
open_outstream(bool force,bool)284*13d37d77SDavid du Colombier open_outstream(bool force, bool)
285*13d37d77SDavid du Colombier {
286*13d37d77SDavid du Colombier int flags = OWRITE;
287*13d37d77SDavid du Colombier
288*13d37d77SDavid du Colombier if (force)
289*13d37d77SDavid du Colombier flags |= OTRUNC;
290*13d37d77SDavid du Colombier else
291*13d37d77SDavid du Colombier flags |= OEXCL;
292*13d37d77SDavid du Colombier
293*13d37d77SDavid du Colombier outfd = create(output_filename, flags, 0666);
294*13d37d77SDavid du Colombier if (outfd >= 0)
295*13d37d77SDavid du Colombier delete_output_on_interrupt = true;
296*13d37d77SDavid du Colombier else if (verbosity >= 0)
297*13d37d77SDavid du Colombier fprintf(stderr, "%s: Can't create output file '%s': %r\n",
298*13d37d77SDavid du Colombier argv0, output_filename);
299*13d37d77SDavid du Colombier return outfd >= 0;
300*13d37d77SDavid du Colombier }
301*13d37d77SDavid du Colombier
302*13d37d77SDavid du Colombier static bool
check_tty(int,enum Mode program_mode)303*13d37d77SDavid du Colombier check_tty(int, enum Mode program_mode)
304*13d37d77SDavid du Colombier {
305*13d37d77SDavid du Colombier if (program_mode == m_compress && isatty(outfd) ||
306*13d37d77SDavid du Colombier program_mode == m_decompress && isatty(infd)) {
307*13d37d77SDavid du Colombier usage();
308*13d37d77SDavid du Colombier return false;
309*13d37d77SDavid du Colombier }
310*13d37d77SDavid du Colombier return true;
311*13d37d77SDavid du Colombier }
312*13d37d77SDavid du Colombier
313*13d37d77SDavid du Colombier void
cleanup_and_fail(int retval)314*13d37d77SDavid du Colombier cleanup_and_fail(int retval)
315*13d37d77SDavid du Colombier {
316*13d37d77SDavid du Colombier if (delete_output_on_interrupt) {
317*13d37d77SDavid du Colombier delete_output_on_interrupt = false;
318*13d37d77SDavid du Colombier if (verbosity >= 0)
319*13d37d77SDavid du Colombier fprintf(stderr, "%s: Deleting output file '%s', if it exists.\n",
320*13d37d77SDavid du Colombier argv0, output_filename);
321*13d37d77SDavid du Colombier if (outfd >= 0) {
322*13d37d77SDavid du Colombier close(outfd);
323*13d37d77SDavid du Colombier outfd = -1;
324*13d37d77SDavid du Colombier }
325*13d37d77SDavid du Colombier if (remove(output_filename) != 0)
326*13d37d77SDavid du Colombier fprintf(stderr, "%s: can't remove output file %s: %r\n",
327*13d37d77SDavid du Colombier argv0, output_filename);
328*13d37d77SDavid du Colombier }
329*13d37d77SDavid du Colombier exit(retval);
330*13d37d77SDavid du Colombier }
331*13d37d77SDavid du Colombier
332*13d37d77SDavid du Colombier /* Set permissions, owner and times. */
333*13d37d77SDavid du Colombier static void
close_and_set_permissions(Dir *)334*13d37d77SDavid du Colombier close_and_set_permissions(Dir *)
335*13d37d77SDavid du Colombier {
336*13d37d77SDavid du Colombier if (close(outfd) != 0) {
337*13d37d77SDavid du Colombier show_error( "Error closing output file", errno, false );
338*13d37d77SDavid du Colombier cleanup_and_fail(1);
339*13d37d77SDavid du Colombier }
340*13d37d77SDavid du Colombier outfd = -1;
341*13d37d77SDavid du Colombier delete_output_on_interrupt = false;
342*13d37d77SDavid du Colombier }
343*13d37d77SDavid du Colombier
344*13d37d77SDavid du Colombier static bool
next_filename(void)345*13d37d77SDavid du Colombier next_filename(void)
346*13d37d77SDavid du Colombier {
347*13d37d77SDavid du Colombier int i, j;
348*13d37d77SDavid du Colombier unsigned name_len = strlen(output_filename);
349*13d37d77SDavid du Colombier unsigned ext_len = strlen(known_extensions[0].from);
350*13d37d77SDavid du Colombier
351*13d37d77SDavid du Colombier if ( name_len >= ext_len + 5 ) /* "*00001.lz" */
352*13d37d77SDavid du Colombier for (i = name_len - ext_len - 1, j = 0; j < 5; --i, ++j) {
353*13d37d77SDavid du Colombier if (output_filename[i] < '9') {
354*13d37d77SDavid du Colombier ++output_filename[i];
355*13d37d77SDavid du Colombier return true;
356*13d37d77SDavid du Colombier } else
357*13d37d77SDavid du Colombier output_filename[i] = '0';
358*13d37d77SDavid du Colombier }
359*13d37d77SDavid du Colombier return false;
360*13d37d77SDavid du Colombier }
361*13d37d77SDavid du Colombier
362*13d37d77SDavid du Colombier typedef struct Poly_encoder Poly_encoder;
363*13d37d77SDavid du Colombier struct Poly_encoder {
364*13d37d77SDavid du Colombier LZ_encoder_base *eb;
365*13d37d77SDavid du Colombier LZ_encoder *e;
366*13d37d77SDavid du Colombier FLZ_encoder *fe;
367*13d37d77SDavid du Colombier };
368*13d37d77SDavid du Colombier
369*13d37d77SDavid du Colombier static int
compress(uvlong member_size,uvlong volume_size,int infd,Lzma_options * encoder_options,Pretty_print * pp,Dir * in_statsp,bool zero)370*13d37d77SDavid du Colombier compress(uvlong member_size, uvlong volume_size,
371*13d37d77SDavid du Colombier int infd, Lzma_options *encoder_options, Pretty_print *pp,
372*13d37d77SDavid du Colombier Dir *in_statsp, bool zero)
373*13d37d77SDavid du Colombier {
374*13d37d77SDavid du Colombier int retval = 0;
375*13d37d77SDavid du Colombier uvlong in_size = 0, out_size = 0, partial_volume_size = 0;
376*13d37d77SDavid du Colombier uvlong cfile_size = in_statsp? in_statsp->length / 100: 0;
377*13d37d77SDavid du Colombier Poly_encoder encoder = { 0, 0, 0 }; /* polymorphic encoder */
378*13d37d77SDavid du Colombier bool error = false;
379*13d37d77SDavid du Colombier
380*13d37d77SDavid du Colombier if (verbosity >= 1)
381*13d37d77SDavid du Colombier Pp_show_msg(pp, 0);
382*13d37d77SDavid du Colombier
383*13d37d77SDavid du Colombier if (zero) {
384*13d37d77SDavid du Colombier encoder.fe = (FLZ_encoder *)malloc(sizeof * encoder.fe);
385*13d37d77SDavid du Colombier if (!encoder.fe || !FLZe_init(encoder.fe, infd, outfd))
386*13d37d77SDavid du Colombier error = true;
387*13d37d77SDavid du Colombier else
388*13d37d77SDavid du Colombier encoder.eb = &encoder.fe->eb;
389*13d37d77SDavid du Colombier } else {
390*13d37d77SDavid du Colombier File_header header;
391*13d37d77SDavid du Colombier
392*13d37d77SDavid du Colombier if (Fh_set_dict_size(header, encoder_options->dict_size) &&
393*13d37d77SDavid du Colombier encoder_options->match_len_limit >= min_match_len_limit &&
394*13d37d77SDavid du Colombier encoder_options->match_len_limit <= max_match_len)
395*13d37d77SDavid du Colombier encoder.e = (LZ_encoder *)malloc(sizeof * encoder.e);
396*13d37d77SDavid du Colombier else
397*13d37d77SDavid du Colombier internal_error( "invalid argument to encoder." );
398*13d37d77SDavid du Colombier if (!encoder.e || !LZe_init(encoder.e, Fh_get_dict_size(header),
399*13d37d77SDavid du Colombier encoder_options->match_len_limit, infd, outfd))
400*13d37d77SDavid du Colombier error = true;
401*13d37d77SDavid du Colombier else
402*13d37d77SDavid du Colombier encoder.eb = &encoder.e->eb;
403*13d37d77SDavid du Colombier }
404*13d37d77SDavid du Colombier if (error) {
405*13d37d77SDavid du Colombier Pp_show_msg( pp, "Not enough memory. Try a smaller dictionary size." );
406*13d37d77SDavid du Colombier return 1;
407*13d37d77SDavid du Colombier }
408*13d37d77SDavid du Colombier
409*13d37d77SDavid du Colombier for(;;) { /* encode one member per iteration */
410*13d37d77SDavid du Colombier uvlong size;
411*13d37d77SDavid du Colombier vlong freevolsz;
412*13d37d77SDavid du Colombier
413*13d37d77SDavid du Colombier size = member_size;
414*13d37d77SDavid du Colombier if (volume_size > 0) {
415*13d37d77SDavid du Colombier freevolsz = volume_size - partial_volume_size;
416*13d37d77SDavid du Colombier if (size > freevolsz)
417*13d37d77SDavid du Colombier size = freevolsz; /* limit size */
418*13d37d77SDavid du Colombier }
419*13d37d77SDavid du Colombier show_progress(in_size, &encoder.eb->mb, pp, cfile_size); /* init */
420*13d37d77SDavid du Colombier if ((zero && !FLZe_encode_member(encoder.fe, size)) ||
421*13d37d77SDavid du Colombier (!zero && !LZe_encode_member(encoder.e, size))) {
422*13d37d77SDavid du Colombier Pp_show_msg( pp, "Encoder error." );
423*13d37d77SDavid du Colombier retval = 1;
424*13d37d77SDavid du Colombier break;
425*13d37d77SDavid du Colombier }
426*13d37d77SDavid du Colombier in_size += Mb_data_position(&encoder.eb->mb);
427*13d37d77SDavid du Colombier out_size += Re_member_position(&encoder.eb->renc);
428*13d37d77SDavid du Colombier if (Mb_data_finished(&encoder.eb->mb))
429*13d37d77SDavid du Colombier break;
430*13d37d77SDavid du Colombier if (volume_size > 0) {
431*13d37d77SDavid du Colombier partial_volume_size += Re_member_position(&encoder.eb->renc);
432*13d37d77SDavid du Colombier if (partial_volume_size >= volume_size - min_dict_size) {
433*13d37d77SDavid du Colombier partial_volume_size = 0;
434*13d37d77SDavid du Colombier if (delete_output_on_interrupt) {
435*13d37d77SDavid du Colombier close_and_set_permissions(in_statsp);
436*13d37d77SDavid du Colombier if (!next_filename()) {
437*13d37d77SDavid du Colombier Pp_show_msg( pp, "Too many volume files." );
438*13d37d77SDavid du Colombier retval = 1;
439*13d37d77SDavid du Colombier break;
440*13d37d77SDavid du Colombier }
441*13d37d77SDavid du Colombier if (!open_outstream(true, !in_statsp)) {
442*13d37d77SDavid du Colombier retval = 1;
443*13d37d77SDavid du Colombier break;
444*13d37d77SDavid du Colombier }
445*13d37d77SDavid du Colombier }
446*13d37d77SDavid du Colombier }
447*13d37d77SDavid du Colombier }
448*13d37d77SDavid du Colombier if (zero)
449*13d37d77SDavid du Colombier FLZe_reset(encoder.fe);
450*13d37d77SDavid du Colombier else
451*13d37d77SDavid du Colombier LZe_reset(encoder.e);
452*13d37d77SDavid du Colombier }
453*13d37d77SDavid du Colombier
454*13d37d77SDavid du Colombier if (retval == 0 && verbosity >= 1)
455*13d37d77SDavid du Colombier if (in_size == 0 || out_size == 0)
456*13d37d77SDavid du Colombier fputs( " no data compressed.\n", stderr );
457*13d37d77SDavid du Colombier else {
458*13d37d77SDavid du Colombier if (0)
459*13d37d77SDavid du Colombier fprintf(stderr,
460*13d37d77SDavid du Colombier "%6.3f:1, %6.3f bits/byte, %5.2f%% saved, ",
461*13d37d77SDavid du Colombier (double)in_size / out_size,
462*13d37d77SDavid du Colombier (8.0 * out_size) / in_size,
463*13d37d77SDavid du Colombier 100.0 * (1.0 - (double)out_size/in_size));
464*13d37d77SDavid du Colombier fprintf(stderr, "%llud in, %llud out.\n",
465*13d37d77SDavid du Colombier in_size, out_size);
466*13d37d77SDavid du Colombier }
467*13d37d77SDavid du Colombier LZeb_free(encoder.eb);
468*13d37d77SDavid du Colombier if (zero)
469*13d37d77SDavid du Colombier free(encoder.fe);
470*13d37d77SDavid du Colombier else
471*13d37d77SDavid du Colombier free(encoder.e);
472*13d37d77SDavid du Colombier return retval;
473*13d37d77SDavid du Colombier }
474*13d37d77SDavid du Colombier
475*13d37d77SDavid du Colombier static uchar
xdigit(unsigned value)476*13d37d77SDavid du Colombier xdigit(unsigned value)
477*13d37d77SDavid du Colombier {
478*13d37d77SDavid du Colombier if (value <= 9)
479*13d37d77SDavid du Colombier return '0' + value;
480*13d37d77SDavid du Colombier if (value <= 15)
481*13d37d77SDavid du Colombier return 'A' + value - 10;
482*13d37d77SDavid du Colombier return 0;
483*13d37d77SDavid du Colombier }
484*13d37d77SDavid du Colombier
485*13d37d77SDavid du Colombier static bool
show_trailing_data(uchar * data,int size,Pretty_print * pp,bool all,bool ignore_trailing)486*13d37d77SDavid du Colombier show_trailing_data(uchar *data, int size, Pretty_print *pp, bool all,
487*13d37d77SDavid du Colombier bool ignore_trailing)
488*13d37d77SDavid du Colombier {
489*13d37d77SDavid du Colombier if (verbosity >= 4 || !ignore_trailing) {
490*13d37d77SDavid du Colombier char buf[128];
491*13d37d77SDavid du Colombier int i, len = snprintf(buf, sizeof buf, "%strailing data = ",
492*13d37d77SDavid du Colombier all? "": "first bytes of ");
493*13d37d77SDavid du Colombier
494*13d37d77SDavid du Colombier if (len < 0)
495*13d37d77SDavid du Colombier len = 0;
496*13d37d77SDavid du Colombier for (i = 0; i < size && len + 2 < sizeof buf; ++i) {
497*13d37d77SDavid du Colombier buf[len++] = xdigit(data[i] >> 4);
498*13d37d77SDavid du Colombier buf[len++] = xdigit(data[i] & 0x0F);
499*13d37d77SDavid du Colombier buf[len++] = ' ';
500*13d37d77SDavid du Colombier }
501*13d37d77SDavid du Colombier if (len < sizeof buf)
502*13d37d77SDavid du Colombier buf[len++] = '\'';
503*13d37d77SDavid du Colombier for (i = 0; i < size && len < sizeof buf; ++i) {
504*13d37d77SDavid du Colombier if (isprint(data[i]))
505*13d37d77SDavid du Colombier buf[len++] = data[i];
506*13d37d77SDavid du Colombier else
507*13d37d77SDavid du Colombier buf[len++] = '.';
508*13d37d77SDavid du Colombier }
509*13d37d77SDavid du Colombier if (len < sizeof buf)
510*13d37d77SDavid du Colombier buf[len++] = '\'';
511*13d37d77SDavid du Colombier if (len < sizeof buf)
512*13d37d77SDavid du Colombier buf[len] = 0;
513*13d37d77SDavid du Colombier else
514*13d37d77SDavid du Colombier buf[sizeof buf - 1] = 0;
515*13d37d77SDavid du Colombier Pp_show_msg(pp, buf);
516*13d37d77SDavid du Colombier if (!ignore_trailing)
517*13d37d77SDavid du Colombier show_file_error(pp->name, trailing_msg, 0);
518*13d37d77SDavid du Colombier }
519*13d37d77SDavid du Colombier return ignore_trailing;
520*13d37d77SDavid du Colombier }
521*13d37d77SDavid du Colombier
522*13d37d77SDavid du Colombier static int
decompress(int infd,Pretty_print * pp,bool ignore_trailing)523*13d37d77SDavid du Colombier decompress(int infd, Pretty_print *pp, bool ignore_trailing)
524*13d37d77SDavid du Colombier {
525*13d37d77SDavid du Colombier uvlong partial_file_pos = 0;
526*13d37d77SDavid du Colombier Range_decoder rdec;
527*13d37d77SDavid du Colombier int retval = 0;
528*13d37d77SDavid du Colombier bool first_member;
529*13d37d77SDavid du Colombier
530*13d37d77SDavid du Colombier if (!Rd_init(&rdec, infd)) {
531*13d37d77SDavid du Colombier show_error( "Not enough memory.", 0, false );
532*13d37d77SDavid du Colombier cleanup_and_fail(1);
533*13d37d77SDavid du Colombier }
534*13d37d77SDavid du Colombier
535*13d37d77SDavid du Colombier for (first_member = true; ; first_member = false) {
536*13d37d77SDavid du Colombier int result, size;
537*13d37d77SDavid du Colombier unsigned dict_size;
538*13d37d77SDavid du Colombier File_header header;
539*13d37d77SDavid du Colombier LZ_decoder decoder;
540*13d37d77SDavid du Colombier
541*13d37d77SDavid du Colombier Rd_reset_member_position(&rdec);
542*13d37d77SDavid du Colombier size = Rd_read_data(&rdec, header, Fh_size);
543*13d37d77SDavid du Colombier if (Rd_finished(&rdec)) /* End Of File */ {
544*13d37d77SDavid du Colombier if (first_member || Fh_verify_prefix(header, size)) {
545*13d37d77SDavid du Colombier Pp_show_msg( pp, "File ends unexpectedly at member header." );
546*13d37d77SDavid du Colombier retval = 2;
547*13d37d77SDavid du Colombier } else if (size > 0 && !show_trailing_data(header, size, pp,
548*13d37d77SDavid du Colombier true, ignore_trailing))
549*13d37d77SDavid du Colombier retval = 2;
550*13d37d77SDavid du Colombier break;
551*13d37d77SDavid du Colombier }
552*13d37d77SDavid du Colombier if (!Fh_verify_magic(header)) {
553*13d37d77SDavid du Colombier if (first_member) {
554*13d37d77SDavid du Colombier show_file_error(pp->name, bad_magic_msg, 0);
555*13d37d77SDavid du Colombier retval = 2;
556*13d37d77SDavid du Colombier } else if (!show_trailing_data(header, size, pp,
557*13d37d77SDavid du Colombier false, ignore_trailing))
558*13d37d77SDavid du Colombier retval = 2;
559*13d37d77SDavid du Colombier break;
560*13d37d77SDavid du Colombier }
561*13d37d77SDavid du Colombier if (!Fh_verify_version(header)) {
562*13d37d77SDavid du Colombier Pp_show_msg(pp, bad_version(Fh_version(header)));
563*13d37d77SDavid du Colombier retval = 2;
564*13d37d77SDavid du Colombier break;
565*13d37d77SDavid du Colombier }
566*13d37d77SDavid du Colombier dict_size = Fh_get_dict_size(header);
567*13d37d77SDavid du Colombier if (!isvalid_ds(dict_size)) {
568*13d37d77SDavid du Colombier Pp_show_msg(pp, bad_dict_msg);
569*13d37d77SDavid du Colombier retval = 2;
570*13d37d77SDavid du Colombier break;
571*13d37d77SDavid du Colombier }
572*13d37d77SDavid du Colombier
573*13d37d77SDavid du Colombier if (verbosity >= 2 || (verbosity == 1 && first_member)) {
574*13d37d77SDavid du Colombier Pp_show_msg(pp, 0);
575*13d37d77SDavid du Colombier show_header(dict_size);
576*13d37d77SDavid du Colombier }
577*13d37d77SDavid du Colombier
578*13d37d77SDavid du Colombier if (!LZd_init(&decoder, &rdec, dict_size, outfd)) {
579*13d37d77SDavid du Colombier Pp_show_msg( pp, "Not enough memory." );
580*13d37d77SDavid du Colombier retval = 1;
581*13d37d77SDavid du Colombier break;
582*13d37d77SDavid du Colombier }
583*13d37d77SDavid du Colombier result = LZd_decode_member(&decoder, pp);
584*13d37d77SDavid du Colombier partial_file_pos += Rd_member_position(&rdec);
585*13d37d77SDavid du Colombier LZd_free(&decoder);
586*13d37d77SDavid du Colombier if (result != 0) {
587*13d37d77SDavid du Colombier if (verbosity >= 0 && result <= 2) {
588*13d37d77SDavid du Colombier Pp_show_msg(pp, 0);
589*13d37d77SDavid du Colombier fprintf(stderr, "%s: %s at pos %llud\n",
590*13d37d77SDavid du Colombier argv0, (result == 2?
591*13d37d77SDavid du Colombier "file ends unexpectedly":
592*13d37d77SDavid du Colombier "decoder error"), partial_file_pos);
593*13d37d77SDavid du Colombier }
594*13d37d77SDavid du Colombier retval = 2;
595*13d37d77SDavid du Colombier break;
596*13d37d77SDavid du Colombier }
597*13d37d77SDavid du Colombier if (verbosity >= 2) {
598*13d37d77SDavid du Colombier fputs("done\n", stderr);
599*13d37d77SDavid du Colombier Pp_reset(pp);
600*13d37d77SDavid du Colombier }
601*13d37d77SDavid du Colombier }
602*13d37d77SDavid du Colombier Rd_free(&rdec);
603*13d37d77SDavid du Colombier if (verbosity == 1 && retval == 0)
604*13d37d77SDavid du Colombier fputs("done\n", stderr);
605*13d37d77SDavid du Colombier return retval;
606*13d37d77SDavid du Colombier }
607*13d37d77SDavid du Colombier
608*13d37d77SDavid du Colombier void
signal_handler(int sig)609*13d37d77SDavid du Colombier signal_handler(int sig)
610*13d37d77SDavid du Colombier {
611*13d37d77SDavid du Colombier USED(sig);
612*13d37d77SDavid du Colombier show_error("interrupt caught, quitting.", 0, false);
613*13d37d77SDavid du Colombier cleanup_and_fail(1);
614*13d37d77SDavid du Colombier }
615*13d37d77SDavid du Colombier
616*13d37d77SDavid du Colombier static void
set_signals(void)617*13d37d77SDavid du Colombier set_signals(void)
618*13d37d77SDavid du Colombier {
619*13d37d77SDavid du Colombier }
620*13d37d77SDavid du Colombier
621*13d37d77SDavid du Colombier void
show_error(char * msg,int,bool help)622*13d37d77SDavid du Colombier show_error(char *msg, int, bool help)
623*13d37d77SDavid du Colombier {
624*13d37d77SDavid du Colombier if (verbosity < 0)
625*13d37d77SDavid du Colombier return;
626*13d37d77SDavid du Colombier if (msg && msg[0])
627*13d37d77SDavid du Colombier fprintf(stderr, "%s: %s: %r\n", argv0, msg);
628*13d37d77SDavid du Colombier if (help)
629*13d37d77SDavid du Colombier fprintf(stderr, "Try '%s --help' for more information.\n",
630*13d37d77SDavid du Colombier argv0);
631*13d37d77SDavid du Colombier }
632*13d37d77SDavid du Colombier
633*13d37d77SDavid du Colombier void
show_file_error(char * filename,char * msg,int errcode)634*13d37d77SDavid du Colombier show_file_error(char *filename, char *msg, int errcode)
635*13d37d77SDavid du Colombier {
636*13d37d77SDavid du Colombier if (verbosity < 0)
637*13d37d77SDavid du Colombier return;
638*13d37d77SDavid du Colombier fprintf(stderr, "%s: %s: %s", argv0, filename, msg);
639*13d37d77SDavid du Colombier if (errcode > 0)
640*13d37d77SDavid du Colombier fprintf(stderr, ": %r");
641*13d37d77SDavid du Colombier fputc('\n', stderr);
642*13d37d77SDavid du Colombier }
643*13d37d77SDavid du Colombier
644*13d37d77SDavid du Colombier void
internal_error(char * msg)645*13d37d77SDavid du Colombier internal_error(char *msg)
646*13d37d77SDavid du Colombier {
647*13d37d77SDavid du Colombier if (verbosity >= 0)
648*13d37d77SDavid du Colombier fprintf( stderr, "%s: internal error: %s\n", argv0, msg );
649*13d37d77SDavid du Colombier exit(3);
650*13d37d77SDavid du Colombier }
651*13d37d77SDavid du Colombier
652*13d37d77SDavid du Colombier void
show_progress(uvlong partial_size,Matchfinder_base * m,Pretty_print * p,uvlong cfile_size)653*13d37d77SDavid du Colombier show_progress(uvlong partial_size, Matchfinder_base *m,
654*13d37d77SDavid du Colombier Pretty_print *p, uvlong cfile_size)
655*13d37d77SDavid du Colombier {
656*13d37d77SDavid du Colombier static uvlong psize = 0, csize = 0; /* csize=file_size/100 */
657*13d37d77SDavid du Colombier static Matchfinder_base *mb = 0;
658*13d37d77SDavid du Colombier static Pretty_print *pp = 0;
659*13d37d77SDavid du Colombier
660*13d37d77SDavid du Colombier if (verbosity < 2)
661*13d37d77SDavid du Colombier return;
662*13d37d77SDavid du Colombier if (m) { /* initialize static vars */
663*13d37d77SDavid du Colombier csize = cfile_size;
664*13d37d77SDavid du Colombier psize = partial_size;
665*13d37d77SDavid du Colombier mb = m;
666*13d37d77SDavid du Colombier pp = p;
667*13d37d77SDavid du Colombier }
668*13d37d77SDavid du Colombier if (mb && pp) {
669*13d37d77SDavid du Colombier uvlong pos = psize + Mb_data_position(mb);
670*13d37d77SDavid du Colombier
671*13d37d77SDavid du Colombier if (csize > 0)
672*13d37d77SDavid du Colombier fprintf( stderr, "%4llud%%", pos / csize );
673*13d37d77SDavid du Colombier fprintf( stderr, " %.1f MB\r", pos / 1000000.0 );
674*13d37d77SDavid du Colombier Pp_reset(pp);
675*13d37d77SDavid du Colombier Pp_show_msg(pp, 0); /* restore cursor position */
676*13d37d77SDavid du Colombier }
677*13d37d77SDavid du Colombier }
678*13d37d77SDavid du Colombier
679*13d37d77SDavid du Colombier /*
680*13d37d77SDavid du Colombier * Mapping from gzip/bzip2 style 1..9 compression modes to the corresponding
681*13d37d77SDavid du Colombier * LZMA compression modes.
682*13d37d77SDavid du Colombier */
683*13d37d77SDavid du Colombier static Lzma_options option_mapping[] = {
684*13d37d77SDavid du Colombier { 1 << 16, 16 },
685*13d37d77SDavid du Colombier { 1 << 20, 5 },
686*13d37d77SDavid du Colombier { 3 << 19, 6 },
687*13d37d77SDavid du Colombier { 1 << 21, 8 },
688*13d37d77SDavid du Colombier { 3 << 20, 12 },
689*13d37d77SDavid du Colombier { 1 << 22, 20 },
690*13d37d77SDavid du Colombier { 1 << 23, 36 },
691*13d37d77SDavid du Colombier { 1 << 24, 68 },
692*13d37d77SDavid du Colombier { 3 << 23, 132 },
693*13d37d77SDavid du Colombier // { 1 << 25, max_match_len }, // TODO
694*13d37d77SDavid du Colombier { 1 << 26, max_match_len },
695*13d37d77SDavid du Colombier };
696*13d37d77SDavid du Colombier
697*13d37d77SDavid du Colombier void
main(int argc,char * argv[])698*13d37d77SDavid du Colombier main(int argc, char *argv[])
699*13d37d77SDavid du Colombier {
700*13d37d77SDavid du Colombier int num_filenames, infd, i, retval = 0;
701*13d37d77SDavid du Colombier bool filenames_given = false, force = false, ignore_trailing = true,
702*13d37d77SDavid du Colombier recompress = false,
703*13d37d77SDavid du Colombier stdin_used = false, to_stdout = false, zero = false;
704*13d37d77SDavid du Colombier uvlong max_member_size = 0x0008000000000000ULL;
705*13d37d77SDavid du Colombier uvlong max_volume_size = 0x4000000000000000ULL;
706*13d37d77SDavid du Colombier uvlong member_size = max_member_size;
707*13d37d77SDavid du Colombier uvlong volume_size = 0;
708*13d37d77SDavid du Colombier char *default_output_filename = "";
709*13d37d77SDavid du Colombier char **filenames = nil;
710*13d37d77SDavid du Colombier enum Mode program_mode = m_compress;
711*13d37d77SDavid du Colombier Lzma_options encoder_options = option_mapping[6]; /* default = "-6" */
712*13d37d77SDavid du Colombier Pretty_print pp;
713*13d37d77SDavid du Colombier
714*13d37d77SDavid du Colombier CRC32_init();
715*13d37d77SDavid du Colombier
716*13d37d77SDavid du Colombier ARGBEGIN {
717*13d37d77SDavid du Colombier case '0':
718*13d37d77SDavid du Colombier case '1':
719*13d37d77SDavid du Colombier case '2':
720*13d37d77SDavid du Colombier case '3':
721*13d37d77SDavid du Colombier case '4':
722*13d37d77SDavid du Colombier case '5':
723*13d37d77SDavid du Colombier case '6':
724*13d37d77SDavid du Colombier case '7':
725*13d37d77SDavid du Colombier case '8':
726*13d37d77SDavid du Colombier case '9':
727*13d37d77SDavid du Colombier zero = (ARGC() == '0');
728*13d37d77SDavid du Colombier encoder_options = option_mapping[ARGC() - '0'];
729*13d37d77SDavid du Colombier break;
730*13d37d77SDavid du Colombier case 'a':
731*13d37d77SDavid du Colombier ignore_trailing = false;
732*13d37d77SDavid du Colombier break;
733*13d37d77SDavid du Colombier case 'b':
734*13d37d77SDavid du Colombier member_size = getnum(EARGF(usage()), 100000, max_member_size);
735*13d37d77SDavid du Colombier break;
736*13d37d77SDavid du Colombier case 'c':
737*13d37d77SDavid du Colombier to_stdout = true;
738*13d37d77SDavid du Colombier break;
739*13d37d77SDavid du Colombier case 'd':
740*13d37d77SDavid du Colombier set_mode(&program_mode, m_decompress);
741*13d37d77SDavid du Colombier break;
742*13d37d77SDavid du Colombier case 'f':
743*13d37d77SDavid du Colombier force = true;
744*13d37d77SDavid du Colombier break;
745*13d37d77SDavid du Colombier case 'F':
746*13d37d77SDavid du Colombier recompress = true;
747*13d37d77SDavid du Colombier break;
748*13d37d77SDavid du Colombier case 'm':
749*13d37d77SDavid du Colombier encoder_options.match_len_limit =
750*13d37d77SDavid du Colombier getnum(EARGF(usage()), min_match_len_limit, max_match_len);
751*13d37d77SDavid du Colombier zero = false;
752*13d37d77SDavid du Colombier break;
753*13d37d77SDavid du Colombier case 'o':
754*13d37d77SDavid du Colombier default_output_filename = EARGF(usage());
755*13d37d77SDavid du Colombier break;
756*13d37d77SDavid du Colombier case 'q':
757*13d37d77SDavid du Colombier verbosity = -1;
758*13d37d77SDavid du Colombier break;
759*13d37d77SDavid du Colombier case 's':
760*13d37d77SDavid du Colombier encoder_options.dict_size = get_dict_size(EARGF(usage()));
761*13d37d77SDavid du Colombier zero = false;
762*13d37d77SDavid du Colombier break;
763*13d37d77SDavid du Colombier case 'S':
764*13d37d77SDavid du Colombier volume_size = getnum(EARGF(usage()), 100000, max_volume_size);
765*13d37d77SDavid du Colombier break;
766*13d37d77SDavid du Colombier case 'v':
767*13d37d77SDavid du Colombier if (verbosity < 4)
768*13d37d77SDavid du Colombier ++verbosity;
769*13d37d77SDavid du Colombier break;
770*13d37d77SDavid du Colombier default:
771*13d37d77SDavid du Colombier usage();
772*13d37d77SDavid du Colombier } ARGEND
773*13d37d77SDavid du Colombier
774*13d37d77SDavid du Colombier num_filenames = max(1, argc);
775*13d37d77SDavid du Colombier filenames = resize_buffer(filenames, num_filenames * sizeof filenames[0]);
776*13d37d77SDavid du Colombier filenames[0] = "-";
777*13d37d77SDavid du Colombier for (i = 0; i < argc; ++i) {
778*13d37d77SDavid du Colombier filenames[i] = argv[i];
779*13d37d77SDavid du Colombier if (strcmp(filenames[i], "-") != 0)
780*13d37d77SDavid du Colombier filenames_given = true;
781*13d37d77SDavid du Colombier }
782*13d37d77SDavid du Colombier
783*13d37d77SDavid du Colombier if (program_mode == m_compress) {
784*13d37d77SDavid du Colombier Dis_slots_init();
785*13d37d77SDavid du Colombier Prob_prices_init();
786*13d37d77SDavid du Colombier }
787*13d37d77SDavid du Colombier
788*13d37d77SDavid du Colombier if (!to_stdout && (filenames_given || default_output_filename[0]))
789*13d37d77SDavid du Colombier set_signals();
790*13d37d77SDavid du Colombier
791*13d37d77SDavid du Colombier Pp_init(&pp, filenames, num_filenames, verbosity);
792*13d37d77SDavid du Colombier
793*13d37d77SDavid du Colombier output_filename = resize_buffer(output_filename, 1);
794*13d37d77SDavid du Colombier for (i = 0; i < num_filenames; ++i) {
795*13d37d77SDavid du Colombier char *input_filename = "";
796*13d37d77SDavid du Colombier int tmp, eindex;
797*13d37d77SDavid du Colombier Dir in_stats;
798*13d37d77SDavid du Colombier Dir *in_statsp;
799*13d37d77SDavid du Colombier
800*13d37d77SDavid du Colombier output_filename[0] = 0;
801*13d37d77SDavid du Colombier if ( !filenames[i][0] || strcmp( filenames[i], "-" ) == 0 ) {
802*13d37d77SDavid du Colombier if (stdin_used)
803*13d37d77SDavid du Colombier continue;
804*13d37d77SDavid du Colombier else
805*13d37d77SDavid du Colombier stdin_used = true;
806*13d37d77SDavid du Colombier infd = 0;
807*13d37d77SDavid du Colombier if (to_stdout || !default_output_filename[0])
808*13d37d77SDavid du Colombier outfd = 1;
809*13d37d77SDavid du Colombier else {
810*13d37d77SDavid du Colombier if (program_mode == m_compress)
811*13d37d77SDavid du Colombier set_c_outname(default_output_filename,
812*13d37d77SDavid du Colombier volume_size > 0);
813*13d37d77SDavid du Colombier else {
814*13d37d77SDavid du Colombier output_filename = resize_buffer(output_filename,
815*13d37d77SDavid du Colombier strlen(default_output_filename)+1);
816*13d37d77SDavid du Colombier strcpy(output_filename,
817*13d37d77SDavid du Colombier default_output_filename);
818*13d37d77SDavid du Colombier }
819*13d37d77SDavid du Colombier if (!open_outstream(force, true)) {
820*13d37d77SDavid du Colombier if (retval < 1)
821*13d37d77SDavid du Colombier retval = 1;
822*13d37d77SDavid du Colombier close(infd);
823*13d37d77SDavid du Colombier continue;
824*13d37d77SDavid du Colombier }
825*13d37d77SDavid du Colombier }
826*13d37d77SDavid du Colombier } else {
827*13d37d77SDavid du Colombier eindex = extension_index(input_filename = filenames[i]);
828*13d37d77SDavid du Colombier infd = open_instream2(input_filename, &in_stats,
829*13d37d77SDavid du Colombier program_mode, eindex, recompress, to_stdout);
830*13d37d77SDavid du Colombier if (infd < 0) {
831*13d37d77SDavid du Colombier if (retval < 1)
832*13d37d77SDavid du Colombier retval = 1;
833*13d37d77SDavid du Colombier continue;
834*13d37d77SDavid du Colombier }
835*13d37d77SDavid du Colombier if (to_stdout)
836*13d37d77SDavid du Colombier outfd = 1;
837*13d37d77SDavid du Colombier else {
838*13d37d77SDavid du Colombier if (program_mode == m_compress)
839*13d37d77SDavid du Colombier set_c_outname(input_filename,
840*13d37d77SDavid du Colombier volume_size > 0);
841*13d37d77SDavid du Colombier else
842*13d37d77SDavid du Colombier set_d_outname(input_filename, eindex);
843*13d37d77SDavid du Colombier if (!open_outstream(force, false)) {
844*13d37d77SDavid du Colombier if (retval < 1)
845*13d37d77SDavid du Colombier retval = 1;
846*13d37d77SDavid du Colombier close(infd);
847*13d37d77SDavid du Colombier continue;
848*13d37d77SDavid du Colombier }
849*13d37d77SDavid du Colombier }
850*13d37d77SDavid du Colombier }
851*13d37d77SDavid du Colombier
852*13d37d77SDavid du Colombier Pp_set_name(&pp, input_filename);
853*13d37d77SDavid du Colombier if (!check_tty(infd, program_mode)) {
854*13d37d77SDavid du Colombier if (retval < 1)
855*13d37d77SDavid du Colombier retval = 1;
856*13d37d77SDavid du Colombier cleanup_and_fail(retval);
857*13d37d77SDavid du Colombier }
858*13d37d77SDavid du Colombier
859*13d37d77SDavid du Colombier in_statsp = input_filename[0]? &in_stats: nil;
860*13d37d77SDavid du Colombier if (program_mode == m_compress)
861*13d37d77SDavid du Colombier tmp = compress(member_size, volume_size, infd,
862*13d37d77SDavid du Colombier &encoder_options, &pp, in_statsp, zero);
863*13d37d77SDavid du Colombier else
864*13d37d77SDavid du Colombier tmp = decompress(infd, &pp, ignore_trailing);
865*13d37d77SDavid du Colombier if (tmp > retval)
866*13d37d77SDavid du Colombier retval = tmp;
867*13d37d77SDavid du Colombier if (tmp)
868*13d37d77SDavid du Colombier cleanup_and_fail(retval);
869*13d37d77SDavid du Colombier
870*13d37d77SDavid du Colombier if (delete_output_on_interrupt)
871*13d37d77SDavid du Colombier close_and_set_permissions(in_statsp);
872*13d37d77SDavid du Colombier if (input_filename[0])
873*13d37d77SDavid du Colombier close(infd);
874*13d37d77SDavid du Colombier }
875*13d37d77SDavid du Colombier if (outfd >= 0 && close(outfd) != 0) {
876*13d37d77SDavid du Colombier show_error("Can't close stdout", errno, false);
877*13d37d77SDavid du Colombier if (retval < 1)
878*13d37d77SDavid du Colombier retval = 1;
879*13d37d77SDavid du Colombier }
880*13d37d77SDavid du Colombier free(output_filename);
881*13d37d77SDavid du Colombier free(filenames);
882*13d37d77SDavid du Colombier exit(retval);
883*13d37d77SDavid du Colombier }
884