📄 deflate.c
字号:
Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM"); memcpy((char*)encoder->window, (char*)encoder->window+WSIZE, (unsigned)WSIZE); encoder->match_start -= WSIZE; encoder->strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ encoder->block_start -= (long) WSIZE; for(n = 0; n < HASH_SIZE; n++) { m = head(n); head(n) = (ush)(m >= WSIZE ? m-WSIZE : NIL); } for(n = 0; n < WSIZE; n++) { m = encoder->prev[n]; encoder->prev[n] = (ush)(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(!encoder->eofile) { n = encoder->read_func((char*)encoder->window+encoder->strstart + encoder->lookahead, (long)more, encoder->user_val); if(n == 0 || n == (unsigned)EOF) { encoder->eofile = 1; } else { encoder->lookahead += n; } }}/* =========================================================================== * Processes a new input file and return its compressed length. This * function does not perform lazy evaluationof matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */local void deflate_fast(DeflateHandler encoder){/* encoder->prev_length = MIN_MATCH-1; encoder->match_length = 0;*/ while(encoder->lookahead != 0 && encoder->qhead == NULL) { int flush; /* set if current block must be flushed */ /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ INSERT_STRING(encoder->strstart, encoder->hash_head); /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if(encoder->hash_head != NIL && encoder->strstart - encoder->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). */ encoder->match_length = longest_match(encoder, encoder->hash_head); /* longest_match() sets match_start */ if(encoder->match_length > encoder->lookahead) encoder->match_length = encoder->lookahead; } if(encoder->match_length >= MIN_MATCH) { check_match(encoder, encoder->strstart, encoder->match_start, encoder->match_length); flush = ct_tally(encoder, encoder->strstart - encoder->match_start, encoder->match_length - MIN_MATCH); encoder->lookahead -= encoder->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ if(encoder->match_length <= encoder->max_lazy_match) { encoder->match_length--; /* string at strstart already in hash table */ do { encoder->strstart++; INSERT_STRING(encoder->strstart, encoder->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 be emitted as literals. */ } while(--encoder->match_length != 0); encoder->strstart++; } else { encoder->strstart += encoder->match_length; encoder->match_length = 0; encoder->ins_h = encoder->window[encoder->strstart]; UPDATE_HASH(encoder->ins_h, encoder->window[encoder->strstart + 1]);#if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times#endif } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c",encoder->window[encoder->strstart])); flush = ct_tally (encoder, 0, encoder->window[encoder->strstart]); encoder->lookahead--; encoder->strstart++; } if(flush) { flush_block(encoder, 0); encoder->block_start = (long)encoder->strstart; } /* 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(encoder->lookahead < MIN_LOOKAHEAD && !encoder->eofile) fill_window(encoder); }}local void deflate_better(DeflateHandler encoder) { /* Process the input block. */ while(encoder->lookahead != 0 && encoder->qhead == NULL) { /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ INSERT_STRING(encoder->strstart, encoder->hash_head); /* Find the longest match, discarding those <= prev_length. */ encoder->prev_length = encoder->match_length; encoder->prev_match = encoder->match_start; encoder->match_length = MIN_MATCH-1; if(encoder->hash_head != NIL && encoder->prev_length < encoder->max_lazy_match && encoder->strstart - encoder->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). */ encoder->match_length = longest_match(encoder, encoder->hash_head); /* longest_match() sets match_start */ if(encoder->match_length > encoder->lookahead) encoder->match_length = encoder->lookahead; /* Ignore a length 3 match if it is too distant: */ if(encoder->match_length == MIN_MATCH && encoder->strstart - encoder->match_start > TOO_FAR){ /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ encoder->match_length--; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if(encoder->prev_length >= MIN_MATCH && encoder->match_length <= encoder->prev_length) { int flush; /* set if current block must be flushed */ check_match(encoder, encoder->strstart-1, encoder->prev_match, encoder->prev_length); flush = ct_tally(encoder, encoder->strstart-1-encoder->prev_match, encoder->prev_length - MIN_MATCH); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. */ encoder->lookahead -= encoder->prev_length-1; encoder->prev_length -= 2; do { encoder->strstart++; INSERT_STRING(encoder->strstart, encoder->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(--encoder->prev_length != 0); encoder->match_available = 0; encoder->match_length = MIN_MATCH-1; encoder->strstart++; if(flush) { flush_block(encoder, 0); encoder->block_start = (long)encoder->strstart; } } else if(encoder->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",encoder->window[encoder->strstart-1])); if(ct_tally (encoder, 0, encoder->window[encoder->strstart-1])) { flush_block(encoder, 0); encoder->block_start = (long)encoder->strstart; } encoder->strstart++; encoder->lookahead--; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ encoder->match_available = 1; encoder->strstart++; encoder->lookahead--; } /* 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(encoder->lookahead < MIN_LOOKAHEAD && !encoder->eofile) fill_window(encoder); }}/*ARGSUSED*/static long default_read_func(char *buf, long size, void *v){ return (long)fread(buf, 1, size, stdin);}DeflateHandler open_deflate_handler( long (* read_func)(char *buf, long size, void *user_val), void *user_val, int level){ DeflateHandler encoder; if(level < 1 || level > 9) return NULL; /* error("bad compression level"); */ encoder = (DeflateHandler)safe_malloc(sizeof(struct _DeflateHandler)); if(encoder == NULL) return NULL; memset(encoder, 0, sizeof(struct _DeflateHandler)); encoder->compr_level = level; if(read_func == NULL) encoder->read_func = default_read_func; else encoder->read_func = read_func; encoder->user_val = user_val; return encoder;}void close_deflate_handler(DeflateHandler encoder){ free(encoder);}local void init_deflate(DeflateHandler encoder){ if(encoder->eofile) return; encoder->bi_buf = 0; encoder->bi_valid = 0; ct_init(encoder); lm_init(encoder); encoder->qhead = NULL; encoder->outcnt = 0; if(encoder->compr_level <= 3) { encoder->prev_length = MIN_MATCH - 1; encoder->match_length = 0; } else { encoder->match_length = MIN_MATCH - 1; encoder->match_available = 0; } encoder->complete = 0;}/* =========================================================================== * 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. */long zip_deflate(DeflateHandler encoder, char *buff, long buff_size){ long n; if(!encoder->initflag) { init_deflate(encoder); encoder->initflag = 1; if(encoder->lookahead == 0) { /* empty */ encoder->complete = 1; return 0; } } if((n = qcopy(encoder, buff, buff_size)) == buff_size) return buff_size; if(encoder->complete) return n; if(encoder->compr_level <= 3) /* optimized for speed */ deflate_fast(encoder); else deflate_better(encoder); if(encoder->lookahead == 0) { if(encoder->match_available) ct_tally(encoder, 0, encoder->window[encoder->strstart - 1]); flush_block(encoder, 1); encoder->complete = 1; } return n + qcopy(encoder, buff + n, buff_size - n);}local long qcopy(DeflateHandler encoder, char *buff, long buff_size){ struct deflate_buff_queue *q; long n, i; n = 0; q = encoder->qhead; while(q != NULL && n < buff_size) { i = buff_size - n; if(i > q->len) i = q->len; memcpy(buff + n, q->ptr, i); q->ptr += i; q->len -= i; n += i; if(q->len == 0) { struct deflate_buff_queue *p; p = q; q = q->next; reuse_queue(p); } } encoder->qhead = q; if(n == buff_size) return n; if(encoder->outoff < encoder->outcnt) { i = buff_size - n; if(i > encoder->outcnt - encoder->outoff) i = encoder->outcnt - encoder->outoff; memcpy(buff + n, encoder->outbuf + encoder->outoff, i); encoder->outoff += i; n += i; if(encoder->outcnt == encoder->outoff) encoder->outcnt = encoder->outoff = 0; } return n;}/* =========================================================================== * Allocate the match buffer, initialize the various tables and save the * location of the internal file attribute (ascii/binary) and method * (DEFLATE/STORE). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -