-/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead, and sets eofile if end of input file.
- * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
- * OUT assertions: at least one byte has been read, or eofile is set;
- * file reads are performed for at least two bytes (required for the
- * translate_eol option).
- */
-static void fill_window(void)
-{
- register unsigned n, m;
- unsigned more =
- (unsigned) (window_size - (ulg) lookahead - (ulg) strstart);
- /* Amount of free space at the end of the window. */
-
- /* If the window is almost full and there is insufficient lookahead,
- * move the upper half to the lower one to make room in the upper half.
- */
- if (more == (unsigned) EOF) {
- /* Very unlikely, but possible on 16 bit machine if strstart == 0
- * and lookahead == 1 (input done one byte at time)
- */
- more--;
- } else if (strstart >= WSIZE + MAX_DIST) {
- /* By the IN assertion, the window is not empty so we can't confuse
- * more == 0 with more == 64K on a 16 bit machine.
- */
- Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM");
-
- memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE);
- match_start -= WSIZE;
- strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */
-
- block_start -= (long) WSIZE;
-
- for (n = 0; n < HASH_SIZE; n++) {
- m = head[n];
- head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
- }
- for (n = 0; n < WSIZE; n++) {
- m = prev[n];
- prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL);
- /* If n is not on any hash chain, prev[n] is garbage but
- * its value will never be used.
- */
- }
- more += WSIZE;
- }
- /* At this point, more >= 2 */
- if (!eofile) {
- n = read_buf((char *) window + strstart + lookahead, more);
- if (n == 0 || n == (unsigned) EOF) {
- eofile = 1;
- } else {
- lookahead += n;
- }
- }
-}
-
-/* ===========================================================================
- * Flush the current block, with given end-of-file flag.
- * IN assertion: strstart is set to the end of the current match.
- */
-#define FLUSH_BLOCK(eof) \
- flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
- (char*)NULL, (long)strstart - block_start, (eof))
-
-/* ===========================================================================
- * Same as above, but achieves better compression. We use a lazy
- * evaluation for matches: a match is finally adopted only if there is
- * no better match at the next window position.
- */
-static ulg deflate(void)
-{
- IPos hash_head; /* head of hash chain */
- IPos prev_match; /* previous match */
- int flush; /* set if current block must be flushed */
- int match_available = 0; /* set if previous match exists */
- register unsigned match_length = MIN_MATCH - 1; /* length of best match */
-
- /* Process the input block. */
- while (lookahead != 0) {
- /* Insert the string window[strstart .. strstart+2] in the
- * dictionary, and set hash_head to the head of the hash chain:
- */
- INSERT_STRING(strstart, hash_head);
-
- /* Find the longest match, discarding those <= prev_length.
- */
- prev_length = match_length, prev_match = match_start;
- match_length = MIN_MATCH - 1;
-
- if (hash_head != NIL && prev_length < max_lazy_match &&
- strstart - hash_head <= MAX_DIST) {
- /* To simplify the code, we prevent matches with the string
- * of window index 0 (in particular we have to avoid a match
- * of the string with itself at the start of the input file).
- */
- match_length = longest_match(hash_head);
- /* longest_match() sets match_start */
- if (match_length > lookahead)
- match_length = lookahead;
-
- /* Ignore a length 3 match if it is too distant: */
- if (match_length == MIN_MATCH && strstart - match_start > TOO_FAR) {
- /* If prev_match is also MIN_MATCH, match_start is garbage
- * but we will ignore the current match anyway.
- */
- match_length--;
- }
- }
- /* If there was a match at the previous step and the current
- * match is not better, output the previous match:
- */
- if (prev_length >= MIN_MATCH && match_length <= prev_length) {
-
- check_match(strstart - 1, prev_match, prev_length);
-
- flush =
- ct_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH);
-
- /* Insert in hash table all strings up to the end of the match.
- * strstart-1 and strstart are already inserted.
- */
- lookahead -= prev_length - 1;
- prev_length -= 2;
- do {
- strstart++;
- INSERT_STRING(strstart, hash_head);
- /* strstart never exceeds WSIZE-MAX_MATCH, so there are
- * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
- * these bytes are garbage, but it does not matter since the
- * next lookahead bytes will always be emitted as literals.
- */
- } while (--prev_length != 0);
- match_available = 0;
- match_length = MIN_MATCH - 1;
- strstart++;
- if (flush)
- FLUSH_BLOCK(0), block_start = strstart;
-
- } else if (match_available) {
- /* If there was no match at the previous position, output a
- * single literal. If there was a match but the current match
- * is longer, truncate the previous match to a single literal.
- */
- Tracevv((stderr, "%c", window[strstart - 1]));
- if (ct_tally(0, window[strstart - 1])) {
- FLUSH_BLOCK(0), block_start = strstart;
- }
- strstart++;
- lookahead--;
- } else {
- /* There is no previous match to compare with, wait for
- * the next step to decide.
- */
- match_available = 1;
- strstart++;
- lookahead--;
- }
- Assert(strstart <= isize && lookahead <= isize, "a bit too far");
-
- /* Make sure that we always have enough lookahead, except
- * at the end of the input file. We need MAX_MATCH bytes
- * for the next match, plus MIN_MATCH bytes to insert the
- * string following the next match.
- */
- while (lookahead < MIN_LOOKAHEAD && !eofile)
- fill_window();
- }
- if (match_available)
- ct_tally(0, window[strstart - 1]);
-
- return FLUSH_BLOCK(1); /* eof */
-}
-
-/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface
- * Copyright (C) 1992-1993 Jean-loup Gailly
- * The unzip code was written and put in the public domain by Mark Adler.
- * Portions of the lzw code are derived from the public domain 'compress'
- * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies,
- * Ken Turkowski, Dave Mack and Peter Jannesen.
- *
- * See the license_msg below and the file COPYING for the software license.
- * See the file algorithm.doc for the compression algorithms and file formats.
- */
-
-/* Compress files with zip algorithm and 'compress' interface.
- * See usage() and help() functions below for all options.
- * Outputs:
- * file.gz: compressed file with same mode, owner, and utimes
- * or stdout with -c option or if stdin used as input.
- * If the output file name had to be truncated, the original name is kept
- * in the compressed file.
- */
-
- /* configuration */
-
-typedef struct dirent dir_type;
-
-/* ======================================================================== */
-int gzip_main(int argc, char **argv)
-{
- int result;
- int inFileNum;
- int outFileNum;
- struct stat statBuf;
- char *delFileName;
- int tostdout = 0;
- int force = 0;
- int opt;
-
- while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) {
- switch (opt) {
- case 'c':
- tostdout = 1;
- break;
- case 'f':
- force = 1;
- break;
- /* Ignore 1-9 (compression level) options */
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- break;
- case 'q':
- break;
-#ifdef CONFIG_GUNZIP
- case 'd':
- optind = 1;
- return gunzip_main(argc, argv);
-#endif
- default:
- bb_show_usage();
- }
- }
-
- foreground = signal(SIGINT, SIG_IGN) != SIG_IGN;
- if (foreground) {
- (void) signal(SIGINT, abort_gzip);
- }
-#ifdef SIGTERM
- if (signal(SIGTERM, SIG_IGN) != SIG_IGN) {
- (void) signal(SIGTERM, abort_gzip);
- }
-#endif
-#ifdef SIGHUP
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
- (void) signal(SIGHUP, abort_gzip);
- }
-#endif
-
- strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1);
- z_len = strlen(z_suffix);
-
- /* Allocate all global buffers (for DYN_ALLOC option) */
- ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA);
- ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA);
- ALLOC(ush, d_buf, DIST_BUFSIZE);
- ALLOC(uch, window, 2L * WSIZE);
- ALLOC(ush, tab_prefix, 1L << BITS);
-
- clear_bufs();
- part_nb = 0;
-
- if (optind == argc) {
- time_stamp = 0;
- ifile_size = -1L;
- zip(STDIN_FILENO, STDOUT_FILENO);
- } else {
- int i;
-
- for (i = optind; i < argc; i++) {
- char *path = NULL;
-
- clear_bufs();
- if (strcmp(argv[i], "-") == 0) {
- time_stamp = 0;
- ifile_size = -1L;
- inFileNum = STDIN_FILENO;
- outFileNum = STDOUT_FILENO;
- } else {
- inFileNum = open(argv[i], O_RDONLY);
- if (inFileNum < 0 || fstat(inFileNum, &statBuf) < 0)
- bb_perror_msg_and_die("%s", argv[i]);
- time_stamp = statBuf.st_ctime;
- ifile_size = statBuf.st_size;
-
- if (!tostdout) {
- path = xmalloc(strlen(argv[i]) + 4);
- strcpy(path, argv[i]);
- strcat(path, ".gz");
-
- /* Open output file */
-#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) && defined O_NOFOLLOW
- outFileNum =
- open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW);
-#else
- outFileNum = open(path, O_RDWR | O_CREAT | O_EXCL);
-#endif
- if (outFileNum < 0) {
- bb_perror_msg("%s", path);
- free(path);
- continue;
- }
-
- /* Set permissions on the file */
- fchmod(outFileNum, statBuf.st_mode);
- } else
- outFileNum = STDOUT_FILENO;
- }
-
- if (path == NULL && isatty(outFileNum) && force == 0) {
- bb_error_msg
- ("compressed data not written to a terminal. Use -f to force compression.");
- free(path);
- continue;
- }
-
- result = zip(inFileNum, outFileNum);
-
- if (path != NULL) {
- close(inFileNum);
- close(outFileNum);
-
- /* Delete the original file */
- if (result == OK)
- delFileName = argv[i];
- else
- delFileName = path;
-
- if (unlink(delFileName) < 0)
- bb_perror_msg("%s", delFileName);
- }
-
- free(path);
- }
- }
-
- return (exit_code);
-}