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