📄 deflate.c
字号:
*/#define UPDATE_HASH(h,c) (h = (((h)<<H_SHIFT) ^ (c)) & HASH_MASK)/* =========================================================================== * Insert string s in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of s are valid * (except for the last MIN_MATCH-1 bytes of the input file). */#define INSERT_STRING(s, match_head) \ (UPDATE_HASH(ins_h, window[(s) + MIN_MATCH-1]), \ prev[(s) & WMASK] = match_head = head[ins_h], \ head[ins_h] = (s))/* =========================================================================== * Initialize the "longest match" routines for a new file * * IN assertion: window_size is > 0 if the input file is already read or * mmap'ed in the window[] array, 0 otherwise. In the first case, * window_size is sufficient to contain the whole input file plus * MIN_LOOKAHEAD bytes (to avoid referencing memory beyond the end * of window[] when looking for matches towards the end). */void lm_init (pack_level, flags) int pack_level; /* 0: store, 1: best speed, 9: best compression */ ush *flags; /* general purpose bit flag */{ 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*) fcalloc(WSIZE, 2*sizeof(uch)); if (window == NULL) err(ZE_MEM, "window allocation"); } if (prev == NULL) { prev = (Pos*) fcalloc(WSIZE, sizeof(Pos)); head = (Pos*) fcalloc(HASH_SIZE, sizeof(Pos)); if (prev == NULL || head == NULL) { err(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 == 1) { *flags |= FAST; } else if (pack_level == 9) { *flags |= SLOW; } /* ??? reduce max_chain_length for binary files */ strstart = 0; block_start = 0L;#ifdef ASMV 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. */ while (lookahead < MIN_LOOKAHEAD && !eofile) 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) { fcfree(window); window = NULL; } if (prev != NULL) { fcfree(prev); fcfree(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 MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or * match.s. The code is functionally equivalent, so you can use the C version * if desired. A 68000 version is in amiga/match_68.a -- this could be used * with other 68000 based systems such as Macintosh with a little effort. */int longest_match(cur_match) IPos cur_match; /* current match */{ unsigned chain_length = max_chain_length; /* max hash chain length */ register uch *scan = window + strstart; /* current string */ register uch *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 *strend = window + strstart + MAX_MATCH - 1; register ush scan_start = *(ush*)scan; register ush scan_end = *(ush*)(scan+best_len-1);#else register uch *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*)(match+best_len-1) != scan_end || *(ush*)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*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(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); 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*)(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",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -