From: Mika Lindqvist Date: Wed, 24 Jun 2015 17:57:34 +0000 (+0300) Subject: Split deflate.c X-Git-Tag: 1.9.9-b1~796^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fc1d0be4bbacdd79ea38c053f6b7301fc175c4bf;p=thirdparty%2Fzlib-ng.git Split deflate.c * Separate common inlines and macros to deflate_p.h * Separate deflate_fast related code to deflate_fast.c * Separate deflate_medium related code to deflate_medium.c * Separate deflate_slow related code to deflate_slow.c --- diff --git a/CMakeLists.txt b/CMakeLists.txt index abcfcfed4..0ec1c0553 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -144,6 +144,9 @@ set(ZLIB_SRCS compress.c crc32.c deflate.c + deflate_fast.c + deflate_medium.c + deflate_slow.c inflate.c infback.c inftrees.c diff --git a/Makefile.in b/Makefile.in index 17c50b70e..d1f4b245e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -66,11 +66,11 @@ mandir = ${prefix}/share/man man3dir = ${mandir}/man3 pkgconfigdir = ${libdir}/pkgconfig -OBJZ = adler32.o compress.o crc32.o deflate.o match.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o $(ARCH_STATIC_OBJS) +OBJZ = adler32.o compress.o crc32.o deflate.o deflate_fast.o deflate_medium.o deflate_slow.o match.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o $(ARCH_STATIC_OBJS) OBJG = gzclose.o gzlib.o gzread.o gzwrite.o OBJC = $(OBJZ) $(OBJG) -PIC_OBJZ = adler32.lo compress.lo crc32.lo deflate.lo match.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo uncompr.lo zutil.lo $(ARCH_SHARED_OBJS) +PIC_OBJZ = adler32.lo compress.lo crc32.lo deflate.lo deflate_fast.lo deflate_medium.lo deflate_slow.lo match.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo uncompr.lo zutil.lo $(ARCH_SHARED_OBJS) PIC_OBJG = gzclose.lo gzlib.lo gzread.lo gzwrite.lo PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG) @@ -334,7 +334,10 @@ adler32.o zutil.o: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h gzclose.o gzlib.o gzread.o gzwrite.o: $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/gzguts.h compress.o example.o minigzip.o uncompr.o: $(SRCDIR)/zlib.h zconf.h crc32.o: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/crc32.h -deflate.o: $(SRCDIR)/deflate.h $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h +deflate.o: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h +deflate_fast.o: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h +deflate_medium.o: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h +deflate_slow.o: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h infback.o inflate.o: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h $(SRCDIR)/inflate.h $(SRCDIR)/inffast.h $(SRCDIR)/inffixed.h inffast.o: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h $(SRCDIR)/inflate.h $(SRCDIR)/inffast.h inftrees.o: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h @@ -344,7 +347,10 @@ adler32.lo zutil.lo: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h gzclose.lo gzlib.lo gzread.lo gzwrite.lo: $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/gzguts.h compress.lo example.lo minigzip.lo uncompr.lo: $(SRCDIR)/zlib.h zconf.h crc32.lo: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/crc32.h -deflate.lo: $(SRCDIR)/deflate.h $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h +deflate.lo: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h +deflate_fast.lo: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h +deflate_medium.lo: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h +deflate_slow.lo: $(SRCDIR)/deflate.h $(SRCDIR)/deflate_p.h $(SRCDIR)/match.h infback.lo inflate.lo: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h $(SRCDIR)/inflate.h $(SRCDIR)/inffast.h $(SRCDIR)/inffixed.h inffast.lo: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h $(SRCDIR)/inflate.h $(SRCDIR)/inffast.h inftrees.lo: $(SRCDIR)/zutil.h $(SRCDIR)/zlib.h zconf.h $(SRCDIR)/inftrees.h diff --git a/deflate.c b/deflate.c index 1d50bb409..fe128cbbe 100644 --- a/deflate.c +++ b/deflate.c @@ -50,12 +50,9 @@ /* @(#) $Id$ */ #include "deflate.h" +#include "deflate_p.h" #include "match.h" -#if defined(X86_CPUID) -# include "arch/x86/x86.h" -#endif - const char deflate_copyright[] = " deflate 1.2.8.f Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome @@ -71,14 +68,14 @@ const char deflate_copyright[] = " deflate 1.2.8.f Copyright 1995-2013 Jean-loup typedef block_state (*compress_func) (deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local void fill_window (deflate_state *s); +void fill_window (deflate_state *s); local block_state deflate_stored (deflate_state *s, int flush); -local block_state deflate_fast (deflate_state *s, int flush); +block_state deflate_fast (deflate_state *s, int flush); block_state deflate_quick (deflate_state *s, int flush); #ifdef MEDIUM_STRATEGY -local block_state deflate_medium (deflate_state *s, int flush); +block_state deflate_medium (deflate_state *s, int flush); #endif -local block_state deflate_slow (deflate_state *s, int flush); +block_state deflate_slow (deflate_state *s, int flush); local block_state deflate_rle (deflate_state *s, int flush); local block_state deflate_huff (deflate_state *s, int flush); local void lm_init (deflate_state *s); @@ -86,10 +83,6 @@ local void putShortMSB (deflate_state *s, uInt b); ZLIB_INTERNAL void flush_pending(z_stream *strm); ZLIB_INTERNAL int read_buf(z_stream *strm, unsigned char *buf, unsigned size); -#ifdef DEBUG -local void check_match(deflate_state *s, IPos start, IPos match, int length); -#endif - extern void crc_reset(deflate_state *const s); extern void crc_finalize(deflate_state *const s); extern void copy_with_crc(z_stream *strm, unsigned char *dst, long size); @@ -101,11 +94,6 @@ extern void copy_with_crc(z_stream *strm, unsigned char *dst, long size); #define NIL 0 /* Tail of hash chains */ -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be @@ -159,76 +147,6 @@ local const config configuration_table[10] = { #define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) -/* =========================================================================== - * Insert string str 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 str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef X86_SSE4_2_CRC_HASH -local inline Pos insert_string_sse(deflate_state *const s, const Pos str, uInt count) { - Pos ret = 0; - uInt idx; - unsigned *ip, val, h = 0; - - for (idx = 0; idx < count; idx++) { - ip = (unsigned *)&s->window[str+idx]; - val = *ip; - h = 0; - - if (s->level >= 6) - val &= 0xFFFFFF; - - __asm__ __volatile__ ( - "crc32 %1,%0\n\t" - : "+r" (h) - : "r" (val) - ); - - ret = s->head[h & s->hash_mask]; - s->head[h & s->hash_mask] = str+idx; - s->prev[(str+idx) & s->w_mask] = ret; - } - return ret; -} -#endif - -local inline Pos insert_string_c(deflate_state *const s, const Pos str, uInt count) { - Pos ret; - uInt idx; - - for (idx = 0; idx < count; idx++) { - UPDATE_HASH(s, s->ins_h, str+idx); - ret = s->prev[(str+idx) & s->w_mask] = s->head[s->ins_h]; - s->head[s->ins_h] = str+idx; - } - return ret; -} - -local inline Pos insert_string(deflate_state *const s, const Pos str) { -#ifdef X86_SSE4_2_CRC_HASH - if (x86_cpu_has_sse42) - return insert_string_sse(s, str, 1); -#endif - return insert_string_c(s, str, 1); -} - - -#ifndef NOT_TWEAK_COMPILER -local inline void bulk_insert_str(deflate_state *const s, Pos startpos, uInt count) { -# ifdef X86_SSE4_2_CRC_HASH - if (x86_cpu_has_sse42) { - insert_string_sse(s, startpos, count); - } else -# endif - { - insert_string_c(s, startpos, count); - } -} -#endif /* NOT_TWEAK_COMPILER */ - /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. @@ -1104,7 +1022,7 @@ local void lm_init(deflate_state *s) { /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(deflate_state *s, IPos start, IPos match, int length) { +void check_match(deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (memcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); @@ -1137,9 +1055,9 @@ local void check_match(deflate_state *s, IPos start, IPos match, int length) { #ifdef X86_SSE2_FILL_WINDOW extern void fill_window_sse(deflate_state *s); #endif -local void fill_window_c(deflate_state *s); +void fill_window_c(deflate_state *s); -local void fill_window(deflate_state *s) { +void fill_window(deflate_state *s) { #ifdef X86_SSE2_FILL_WINDOW # ifndef X86_NOCHECK_SSE2 if (x86_cpu_has_sse2) { @@ -1156,7 +1074,7 @@ local void fill_window(deflate_state *s) { #endif } -local void fill_window_c(deflate_state *s) { +void fill_window_c(deflate_state *s) { register unsigned n; register Pos *p; unsigned more; /* Amount of free space at the end of the window. */ @@ -1314,27 +1232,6 @@ local void fill_window_c(deflate_state *s) { "not enough room for search"); } -/* =========================================================================== - * 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_ONLY(s, last) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (char *)&s->window[(unsigned)s->block_start] : \ - (char *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (last)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr, "[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, last) { \ - FLUSH_BLOCK_ONLY(s, last); \ - if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ -} - /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. @@ -1398,257 +1295,6 @@ local block_state deflate_stored(deflate_state *s, int flush) { return block_done; } -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of 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 block_state deflate_fast(deflate_state *s, int flush) { - IPos hash_head; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* 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. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) - break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - hash_head = insert_string(s, s->strstart); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* 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). - */ - s->match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->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 (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - s->strstart++; -#ifdef NOT_TWEAK_COMPILER - do { - insert_string(s, s->strstart); - s->strstart++; - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); -#else - { - bulk_insert_str(s, s->strstart, s->match_length); - s->strstart += s->match_length; - s->match_length = 0; - } -#endif - } else { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->strstart+2 - (MIN_MATCH)); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr, "%c", s->window[s->strstart])); - _tr_tally_lit(s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) - FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - - -#ifdef MEDIUM_STRATEGY -#include "deflate_medium.c" -#endif - -/* =========================================================================== - * 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. - */ -local block_state deflate_slow(deflate_state *s, int flush) { - IPos hash_head; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* 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. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) - break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - hash_head = insert_string(s, s->strstart); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { - /* 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). - */ - s->match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - -#ifdef NOT_TWEAK_COMPILER - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - hash_head = insert_string(s, s->strstart); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; -#else - { - uInt mov_fwd = s->prev_length - 2; - uInt insert_cnt = mov_fwd; - if (unlikely(insert_cnt > max_insert - s->strstart)) - insert_cnt = max_insert - s->strstart; - - bulk_insert_str(s, s->strstart + 1, insert_cnt); - s->prev_length = 0; - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart += mov_fwd + 1; - } -#endif /*NOT_TWEAK_COMPILER*/ - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->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", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) - return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert(flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr, "%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance diff --git a/deflate_fast.c b/deflate_fast.c new file mode 100644 index 000000000..edfe53d7f --- /dev/null +++ b/deflate_fast.c @@ -0,0 +1,114 @@ +/* deflate_fast.c -- compress data using the fast strategy of deflation algorithm + * + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "deflate.h" +#include "deflate_p.h" +#include "match.h" + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of 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. + */ +block_state deflate_fast(deflate_state *s, int flush) { + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* 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. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + hash_head = insert_string(s, s->strstart); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* 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). + */ + s->match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->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 (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + s->strstart++; +#ifdef NOT_TWEAK_COMPILER + do { + insert_string(s, s->strstart); + s->strstart++; + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); +#else + { + bulk_insert_str(s, s->strstart, s->match_length); + s->strstart += s->match_length; + s->match_length = 0; + } +#endif + } else { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->strstart+2 - (MIN_MATCH)); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr, "%c", s->window[s->strstart])); + _tr_tally_lit(s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) + FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/deflate_medium.c b/deflate_medium.c index c3cd1a27e..b04abdbbe 100644 --- a/deflate_medium.c +++ b/deflate_medium.c @@ -7,7 +7,10 @@ * * For conditions of distribution and use, see copyright notice in zlib.h */ +#ifdef MEDIUM_STRATEGY #include "deflate.h" +#include "deflate_p.h" +#include "match.h" struct match { uInt match_start; @@ -287,3 +290,4 @@ block_state deflate_medium(deflate_state *s, int flush) { return block_done; } +#endif diff --git a/deflate_p.h b/deflate_p.h new file mode 100644 index 000000000..e43f1be03 --- /dev/null +++ b/deflate_p.h @@ -0,0 +1,116 @@ +/* deflate_p.h -- Private inline functions and macros shared with more than + * one deflate method + * + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + */ + +#ifndef DEFLATE_P_H +#define DEFLATE_P_H + +#if defined(X86_CPUID) +# include "arch/x86/x86.h" +#endif + +/* Forward declare common non-inlined functions declared in deflate.c */ + +#ifdef DEBUG +void check_match(deflate_state *s, IPos start, IPos match, int length); +#else +#define check_match(s, start, match, length) +#endif +void fill_window(deflate_state *s); +void flush_pending(z_stream *strm); + +/* =========================================================================== + * Insert string str 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 str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef X86_SSE4_2_CRC_HASH +local inline Pos insert_string_sse(deflate_state *const s, const Pos str, uInt count) { + Pos ret = 0; + uInt idx; + unsigned *ip, val, h = 0; + + for (idx = 0; idx < count; idx++) { + ip = (unsigned *)&s->window[str+idx]; + val = *ip; + h = 0; + + if (s->level >= 6) + val &= 0xFFFFFF; + + __asm__ __volatile__ ( + "crc32 %1,%0\n\t" + : "+r" (h) + : "r" (val) + ); + + ret = s->head[h & s->hash_mask]; + s->head[h & s->hash_mask] = str+idx; + s->prev[(str+idx) & s->w_mask] = ret; + } + return ret; +} +#endif + +local inline Pos insert_string_c(deflate_state *const s, const Pos str, uInt count) { + Pos ret; + uInt idx; + + for (idx = 0; idx < count; idx++) { + UPDATE_HASH(s, s->ins_h, str+idx); + ret = s->prev[(str+idx) & s->w_mask] = s->head[s->ins_h]; + s->head[s->ins_h] = str+idx; + } + return ret; +} + +local inline Pos insert_string(deflate_state *const s, const Pos str) { +#ifdef X86_SSE4_2_CRC_HASH + if (x86_cpu_has_sse42) + return insert_string_sse(s, str, 1); +#endif + return insert_string_c(s, str, 1); +} + +#ifndef NOT_TWEAK_COMPILER +local inline void bulk_insert_str(deflate_state *const s, Pos startpos, uInt count) { +# ifdef X86_SSE4_2_CRC_HASH + if (x86_cpu_has_sse42) { + insert_string_sse(s, startpos, count); + } else +# endif + { + insert_string_c(s, startpos, count); + } +} +#endif /* NOT_TWEAK_COMPILER */ + +/* =========================================================================== + * 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_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (char *)&s->window[(unsigned)s->block_start] : \ + (char *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr, "[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +#endif diff --git a/deflate_slow.c b/deflate_slow.c new file mode 100644 index 000000000..6c212342b --- /dev/null +++ b/deflate_slow.c @@ -0,0 +1,160 @@ +/* deflate_slow.c -- compress data using the slow strategy of deflation algorithm + * + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "deflate.h" +#include "deflate_p.h" +#include "match.h" + +/* =========================================================================== + * Local data + */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* =========================================================================== + * Same as deflate_medium, 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. + */ +block_state deflate_slow(deflate_state *s, int flush) { + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* 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. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + hash_head = insert_string(s, s->strstart); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { + /* 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). + */ + s->match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + +#ifdef NOT_TWEAK_COMPILER + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + hash_head = insert_string(s, s->strstart); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; +#else + { + uInt mov_fwd = s->prev_length - 2; + uInt insert_cnt = mov_fwd; + if (unlikely(insert_cnt > max_insert - s->strstart)) + insert_cnt = max_insert - s->strstart; + + bulk_insert_str(s, s->strstart + 1, insert_cnt); + s->prev_length = 0; + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart += mov_fwd + 1; + } +#endif /*NOT_TWEAK_COMPILER*/ + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->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", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) + return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert(flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr, "%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +}