]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Split deflate.c
authorMika Lindqvist <postmaster@raasu.org>
Wed, 24 Jun 2015 17:57:34 +0000 (20:57 +0300)
committerHans Kristian Rosbach <hk-git@circlestorm.org>
Wed, 24 Jun 2015 18:34:55 +0000 (20:34 +0200)
* 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

CMakeLists.txt
Makefile.in
deflate.c
deflate_fast.c [new file with mode: 0644]
deflate_medium.c
deflate_p.h [new file with mode: 0644]
deflate_slow.c [new file with mode: 0644]

index abcfcfed4da7ae4ecb39360f86e4a213efb2428c..0ec1c055385a636cfbad1f851ffe6da8d5b76136 100644 (file)
@@ -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
index 17c50b70e0bf11fb64ef1bcfbd7ccdbf9e066c64..d1f4b245edbdfda46e12495e443c451586ae3e72 100644 (file)
@@ -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
index 1d50bb409fc273b3a0fe9655d23631673a418268..fe128cbbee430107732d2459240a74a721d56c6b 100644 (file)
--- a/deflate.c
+++ b/deflate.c
 /* @(#) $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 (file)
index 0000000..edfe53d
--- /dev/null
@@ -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;
+}
index c3cd1a27e8a5ca87cda75e347f0e5b758f61dc66..b04abdbbea39cfab6bcd360a2e48ae77c0af84ba 100644 (file)
@@ -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 (file)
index 0000000..e43f1be
--- /dev/null
@@ -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 (file)
index 0000000..6c21234
--- /dev/null
@@ -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;
+}