📄 deflate.c
字号:
register unsigned j; if (pack_level < 1 || pack_level > 9) error("bad pack level"); /* Do not slide the window if the whole input is already in memory * (window_size > 0) */ sliding = 0; if (window_size == 0L) { sliding = 1; window_size = (ulg)2L*WSIZE; } /* Use dynamic allocation if compiler does not like big static arrays: */#ifdef DYN_ALLOC if (window == NULL) { window = (uch far *) zcalloc(WSIZE, 2*sizeof(uch)); if (window == NULL) ziperr(ZE_MEM, "window allocation"); } if (prev == NULL) { prev = (Pos far *) zcalloc(WSIZE, sizeof(Pos)); head = (Pos far *) zcalloc(HASH_SIZE, sizeof(Pos)); if (prev == NULL || head == NULL) { ziperr(ZE_MEM, "hash table allocation"); } }#endif /* DYN_ALLOC */ /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ head[HASH_SIZE-1] = NIL; memset((char*)head, NIL, (unsigned)(HASH_SIZE-1)*sizeof(*head)); /* Set the default configuration parameters: */ max_lazy_match = configuration_table[pack_level].max_lazy; good_match = configuration_table[pack_level].good_length;#ifndef FULL_SEARCH nice_match = configuration_table[pack_level].nice_length;#endif max_chain_length = configuration_table[pack_level].max_chain; if (pack_level <= 2) { *flags |= FAST; } else if (pack_level >= 8) { *flags |= SLOW; } /* ??? reduce max_chain_length for binary files */ strstart = 0; block_start = 0L;#if defined(ASMV) && !defined(RISCOS) match_init(); /* initialize the asm code */#endif j = WSIZE;#ifndef MAXSEG_64K if (sizeof(int) > 2) j <<= 1; /* Can read 64K in one step */#endif lookahead = (*read_buf)((char*)window, j); if (lookahead == 0 || lookahead == (unsigned)EOF) { eofile = 1, lookahead = 0; return; } eofile = 0; /* Make sure that we always have enough lookahead. This is important * if input comes from a device such as a tty. */ if (lookahead < MIN_LOOKAHEAD) fill_window(); ins_h = 0; for (j=0; j<MIN_MATCH-1; j++) UPDATE_HASH(ins_h, window[j]); /* If lookahead < MIN_MATCH, ins_h is garbage, but this is * not important since only literal bytes will be emitted. */}/* =========================================================================== * Free the window and hash table */void lm_free(){#ifdef DYN_ALLOC if (window != NULL) { zcfree(window); window = NULL; } if (prev != NULL) { zcfree(prev); zcfree(head); prev = head = NULL; }#endif /* DYN_ALLOC */}/* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 */#ifndef ASMV/* For 80x86 and 680x0 and ARM, an optimized version is in match.asm or * match.S. The code is functionally equivalent, so you can use the C version * if desired. */int longest_match(cur_match) IPos cur_match; /* current match */{ unsigned chain_length = max_chain_length; /* max hash chain length */ register uch far *scan = window + strstart; /* current string */ register uch far *match; /* matched string */ register int len; /* length of current match */ int best_len = prev_length; /* best match length so far */ IPos limit = strstart > (IPos)MAX_DIST ? strstart - (IPos)MAX_DIST : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. *//* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */#if HASH_BITS < 8 || MAX_MATCH != 258 error: Code too clever#endif#ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register uch far *strend = window + strstart + MAX_MATCH - 1; register ush scan_start = *(ush far *)scan; register ush scan_end = *(ush far *)(scan+best_len-1);#else register uch far *strend = window + strstart + MAX_MATCH; register uch scan_end1 = scan[best_len-1]; register uch scan_end = scan[best_len];#endif /* Do not waste too much time if we already have a good match: */ if (prev_length >= good_match) { chain_length >>= 2; } Assert(strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead"); do { Assert(cur_match < strstart, "no future"); match = window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2: */#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ush far *)(match+best_len-1) != scan_end || *(ush far *)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ scan++, match++; do { } while (*(ush far *)(scan+=2) == *(ush far *)(match+=2) && *(ush far *)(scan+=2) == *(ush far *)(match+=2) && *(ush far *)(scan+=2) == *(ush far *)(match+=2) && *(ush far *)(scan+=2) == *(ush far *)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= window+(unsigned)(window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1);#else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= window+(unsigned)(window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH;#endif /* UNALIGNED_OK */ if (len > best_len) { match_start = cur_match; best_len = len; if (len >= nice_match) break;#ifdef UNALIGNED_OK scan_end = *(ush far *)(scan+best_len-1);#else scan_end1 = scan[best_len-1]; scan_end = scan[best_len];#endif } } while ((cur_match = prev[cur_match & WMASK]) > limit && --chain_length != 0); return best_len;}#endif /* ASMV */#ifdef DEBUG/* =========================================================================== * Check that the match at match_start is indeed a match. */local void check_match(start, match, length) IPos start, match; int length;{ /* check that the match is indeed a match */ if (memcmp((char*)window + match, (char*)window + start, length) != EQUAL) { fprintf(stderr, " start %d, match %d, length %d\n", start, match, length); error("invalid match"); } if (verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length);#ifndef WINDLL do { putc(window[start++], stderr); } while (--length != 0);#else do { fprintf(stdout,"%c",window[start++]); } while (--length != 0);#endif }}#else# define check_match(start, match, length)#endif/* =========================================================================== * 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, (ulg)strstart - (ulg)block_start, (eof))/* =========================================================================== * 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: strstart <= window_size-MIN_LOOKAHEAD * 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). */local void fill_window(){ register unsigned n, m; unsigned more; /* Amount of free space at the end of the window. */ do { more = (unsigned)(window_size - (ulg)lookahead - (ulg)strstart); /* 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--; /* For MMAP or BIG_MEM, the whole input file is already in memory so * we must not perform sliding. We must however call (*read_buf)() in
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -