-/* ===========================================================================
- * 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)
-{
- unsigned n, m;
- unsigned more = window_size - lookahead - 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) -1) {
- /* 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(window, window + WSIZE, 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 = file_read(window + strstart + lookahead, more);
- if (n == 0 || n == (unsigned) -1) {
- 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.
- *
- * Processes a new input file and return its compressed length. Sets
- * the compressed length, crc, deflate flags and internal file
- * attributes.
- */
-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 */
- 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 != 0 && 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 */
-}
-
-
-/* ======================================================================== */
-static void abort_gzip(int ATTRIBUTE_UNUSED ignored)
-{
- exit(1);
-}
-
-int gzip_main(int argc, char **argv)
-{
- enum {
- OPT_tostdout = 0x1,
- OPT_force = 0x2,
- };
-
- unsigned opt;
- int result;
- int inFileNum;
- int outFileNum;
- struct stat statBuf;
- char *delFileName;
-
- opt = getopt32(argc, argv, "cf123456789qv" USE_GUNZIP("d"));
- //if (opt & 0x1) // -c
- //if (opt & 0x2) // -f
- /* Ignore 1-9 (compression level) options */
- //if (opt & 0x4) // -1
- //if (opt & 0x8) // -2
- //if (opt & 0x10) // -3
- //if (opt & 0x20) // -4
- //if (opt & 0x40) // -5
- //if (opt & 0x80) // -6
- //if (opt & 0x100) // -7
- //if (opt & 0x200) // -8
- //if (opt & 0x400) // -9
- //if (opt & 0x800) // -q
- //if (opt & 0x1000) // -v
-#if ENABLE_GUNZIP /* gunzip_main may not be visible... */
- if (opt & 0x2000) { // -d
- /* FIXME: getopt32 should not depend on optind */
- optind = 1;
- return gunzip_main(argc, argv);
- }
-#endif
-
- 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, ".gz", sizeof(z_suffix) - 1);
-
- /* 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);
-
- /* Initialise the CRC32 table */
- crc_32_tab = crc32_filltable(0);
-
- clear_bufs();
-
- if (optind == argc) {
- time_stamp = 0;
- zip(STDIN_FILENO, STDOUT_FILENO);
- } else {
- int i;
-
- for (i = optind; i < argc; i++) {
- char *path = NULL;
-
- clear_bufs();
- if (LONE_DASH(argv[i])) {
- time_stamp = 0;
- inFileNum = STDIN_FILENO;
- outFileNum = STDOUT_FILENO;
- } else {
- inFileNum = xopen(argv[i], O_RDONLY);
- if (fstat(inFileNum, &statBuf) < 0)
- bb_perror_msg_and_die("%s", argv[i]);
- time_stamp = statBuf.st_ctime;
-
- if (!(opt & OPT_tostdout)) {
- path = xasprintf("%s.gz", argv[i]);
-
- /* Open output file */
-#if defined(__GLIBC__) && __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) && !(opt & OPT_force)) {
- 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 == 0)
- delFileName = argv[i];
- else
- delFileName = path;
-
- if (unlink(delFileName) < 0)
- bb_perror_msg("%s", delFileName);
- }
-
- free(path);
- }
- }
-
- return exit_code;
-}