fix for gzip man page pack reference
[debian/gzip] / deflate.c
index 2f55a7cc8b8fa5b7bb50cff8ee41d469e1a5afa3..a551fa3a409d640905fed9e329d10038731f13a5 100644 (file)
--- a/deflate.c
+++ b/deflate.c
@@ -1,11 +1,11 @@
 /* deflate.c -- compress data using the deflation algorithm
 
 /* deflate.c -- compress data using the deflation algorithm
 
-   Copyright (C) 1999, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2006, 2009-2010 Free Software Foundation, Inc.
    Copyright (C) 1992-1993 Jean-loup Gailly
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Copyright (C) 1992-1993 Jean-loup Gailly
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
    any later version.
 
    This program is distributed in the hope that it will be useful,
 #include "gzip.h"
 #include "lzw.h" /* just for consistency checking */
 
 #include "gzip.h"
 #include "lzw.h" /* just for consistency checking */
 
-#ifdef RCSID
-static char rcsid[] = "$Id: deflate.c,v 1.5 2006/12/07 23:53:00 eggert Exp $";
-#endif
-
 /* ===========================================================================
  * Configuration parameters
  */
 /* ===========================================================================
  * Configuration parameters
  */
@@ -135,6 +131,14 @@ static char rcsid[] = "$Id: deflate.c,v 1.5 2006/12/07 23:53:00 eggert Exp $";
 #endif
 /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
 
 #endif
 /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
 
+#ifndef RSYNC_WIN
+#  define RSYNC_WIN 8192
+#endif
+/* Size of rsync window, must be < MAX_DIST */
+
+#define RSYNC_SUM_MATCH(sum) (((sum) & (RSYNC_WIN - 1)) == 0)
+/* Whether window sum matches magic value */
+
 /* ===========================================================================
  * Local data used by the "longest match" routines.
  */
 /* ===========================================================================
  * Local data used by the "longest match" routines.
  */
@@ -216,6 +220,8 @@ local int compr_level;
 unsigned near good_match;
 /* Use a faster search when the previous match is longer than this */
 
 unsigned near good_match;
 /* Use a faster search when the previous match is longer than this */
 
+local ulg rsync_sum;  /* rolling sum of rsync window */
+local ulg rsync_chunk_end; /* next rsync sequence point */
 
 /* 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
 
 /* 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
@@ -255,9 +261,6 @@ local config configuration_table[10] = {
  * meaning.
  */
 
  * meaning.
  */
 
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
 /* ===========================================================================
  *  Prototypes for local functions.
  */
 /* ===========================================================================
  *  Prototypes for local functions.
  */
@@ -314,6 +317,10 @@ void lm_init (pack_level, flags)
 #endif
     /* prev will be initialized on the fly */
 
 #endif
     /* prev will be initialized on the fly */
 
+    /* rsync params */
+    rsync_chunk_end = 0xFFFFFFFFUL;
+    rsync_sum = 0;
+
     /* Set the default configuration parameters:
      */
     max_lazy_match   = configuration_table[pack_level].max_lazy;
     /* Set the default configuration parameters:
      */
     max_lazy_match   = configuration_table[pack_level].max_lazy;
@@ -331,6 +338,7 @@ void lm_init (pack_level, flags)
 
     strstart = 0;
     block_start = 0L;
 
     strstart = 0;
     block_start = 0L;
+    rsync_chunk_end = 0xFFFFFFFFUL;
 #ifdef ASMV
     match_init(); /* initialize the asm code */
 #endif
 #ifdef ASMV
     match_init(); /* initialize the asm code */
 #endif
@@ -504,7 +512,7 @@ local void check_match(start, match, length)
 {
     /* check that the match is indeed a match */
     if (memcmp((char*)window + match,
 {
     /* check that the match is indeed a match */
     if (memcmp((char*)window + match,
-                (char*)window + start, length) != EQUAL) {
+                (char*)window + start, length) != 0) {
         fprintf(stderr,
             " start %d, match %d, length %d\n",
             start, match, length);
         fprintf(stderr,
             " start %d, match %d, length %d\n",
             start, match, length);
@@ -550,6 +558,8 @@ local void fill_window()
         memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
         match_start -= WSIZE;
         strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
         memcpy((char*)window, (char*)window+WSIZE, (unsigned)WSIZE);
         match_start -= WSIZE;
         strstart    -= WSIZE; /* we now have strstart >= MAX_DIST: */
+       if (rsync_chunk_end != 0xFFFFFFFFUL)
+           rsync_chunk_end -= WSIZE;
 
         block_start -= (long) WSIZE;
 
 
         block_start -= (long) WSIZE;
 
@@ -571,12 +581,47 @@ local void fill_window()
         n = read_buf((char*)window+strstart+lookahead, more);
         if (n == 0 || n == (unsigned)EOF) {
             eofile = 1;
         n = read_buf((char*)window+strstart+lookahead, more);
         if (n == 0 || n == (unsigned)EOF) {
             eofile = 1;
+            /* Don't let garbage pollute the dictionary.  */
+            memzero (window + strstart + lookahead, MIN_MATCH - 1);
         } else {
             lookahead += n;
         }
     }
 }
 
         } else {
             lookahead += n;
         }
     }
 }
 
+local void rsync_roll(start, num)
+    unsigned start;
+    unsigned num;
+{
+    unsigned i;
+
+    if (start < RSYNC_WIN) {
+       /* before window fills. */
+       for (i = start; i < RSYNC_WIN; i++) {
+           if (i == start + num) return;
+           rsync_sum += (ulg)window[i];
+       }
+       num -= (RSYNC_WIN - start);
+       start = RSYNC_WIN;
+    }
+
+    /* buffer after window full */
+    for (i = start; i < start+num; i++) {
+       /* New character in */
+       rsync_sum += (ulg)window[i];
+       /* Old character out */
+       rsync_sum -= (ulg)window[i - RSYNC_WIN];
+       if (rsync_chunk_end == 0xFFFFFFFFUL && RSYNC_SUM_MATCH(rsync_sum))
+           rsync_chunk_end = i;
+    }
+}
+
+/* ===========================================================================
+ * Set rsync_chunk_end if window sum matches magic value.
+ */
+#define RSYNC_ROLL(s, n) \
+   do { if (rsync) rsync_roll((s), (n)); } while(0)
+
 /* ===========================================================================
  * Flush the current block, with given end-of-file flag.
  * IN assertion: strstart is set to the end of the current match.
 /* ===========================================================================
  * Flush the current block, with given end-of-file flag.
  * IN assertion: strstart is set to the end of the current match.
@@ -624,6 +669,7 @@ local off_t deflate_fast()
 
             lookahead -= match_length;
 
 
             lookahead -= match_length;
 
+           RSYNC_ROLL(strstart, match_length);
            /* Insert new strings in the hash table only if the match length
              * is not too large. This saves time but degrades compression.
              */
            /* Insert new strings in the hash table only if the match length
              * is not too large. This saves time but degrades compression.
              */
@@ -652,9 +698,18 @@ local off_t deflate_fast()
             /* No match, output a literal byte */
             Tracevv((stderr,"%c",window[strstart]));
             flush = ct_tally (0, window[strstart]);
             /* No match, output a literal byte */
             Tracevv((stderr,"%c",window[strstart]));
             flush = ct_tally (0, window[strstart]);
+           RSYNC_ROLL(strstart, 1);
             lookahead--;
            strstart++;
         }
             lookahead--;
            strstart++;
         }
+        if (rsync && strstart > rsync_chunk_end) {
+            ush  attr = 0;          /* ascii/binary flag */
+
+            flush = 1;
+            /* Reset huffman tree */
+            ct_init(&attr, &method);
+            rsync_chunk_end = 0xFFFFFFFFUL;
+        }
         if (flush) FLUSH_BLOCK(0), block_start = strstart;
 
         /* Make sure that we always have enough lookahead, except
         if (flush) FLUSH_BLOCK(0), block_start = strstart;
 
         /* Make sure that we always have enough lookahead, except
@@ -728,6 +783,7 @@ off_t deflate()
              */
             lookahead -= prev_length-1;
             prev_length -= 2;
              */
             lookahead -= prev_length-1;
             prev_length -= 2;
+           RSYNC_ROLL(strstart, prev_length+1);
             do {
                 strstart++;
                 INSERT_STRING(strstart, hash_head);
             do {
                 strstart++;
                 INSERT_STRING(strstart, hash_head);
@@ -740,24 +796,51 @@ off_t deflate()
             match_available = 0;
             match_length = MIN_MATCH-1;
             strstart++;
             match_available = 0;
             match_length = MIN_MATCH-1;
             strstart++;
-            if (flush) FLUSH_BLOCK(0), block_start = strstart;
 
 
+           if (rsync && strstart > rsync_chunk_end) {
+               ush  attr = 0;          /* ascii/binary flag */
+
+               /* Reset huffman tree */
+               ct_init(&attr, &method);
+               rsync_chunk_end = 0xFFFFFFFFUL;
+               flush = 1;
+           }
+            if (flush) FLUSH_BLOCK(0), block_start = strstart;
         } else if (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",window[strstart-1]));
         } else if (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",window[strstart-1]));
-            if (ct_tally (0, window[strstart-1])) {
-                FLUSH_BLOCK(0), block_start = strstart;
-            }
+           flush = ct_tally (0, window[strstart-1]);
+           if (rsync && strstart > rsync_chunk_end) {
+               ush  attr = 0;          /* ascii/binary flag */
+
+               /* Reset huffman tree */
+               ct_init(&attr, &method);
+               rsync_chunk_end = 0xFFFFFFFFUL;
+
+               flush = 1;
+           }
+            if (flush) FLUSH_BLOCK(0), block_start = strstart;
+           RSYNC_ROLL(strstart, 1);
             strstart++;
             lookahead--;
         } else {
             /* There is no previous match to compare with, wait for
              * the next step to decide.
              */
             strstart++;
             lookahead--;
         } else {
             /* There is no previous match to compare with, wait for
              * the next step to decide.
              */
+           if (rsync && strstart > rsync_chunk_end) {
+               ush  attr = 0;          /* ascii/binary flag */
+
+               /* Reset huffman tree */
+               ct_init(&attr, &method);
+               rsync_chunk_end = 0xFFFFFFFFUL;
+
+               FLUSH_BLOCK(0), block_start = strstart;
+           }
             match_available = 1;
             match_available = 1;
+           RSYNC_ROLL(strstart, 1);
             strstart++;
             lookahead--;
         }
             strstart++;
             lookahead--;
         }