+++ /dev/null
---- gzip-1.3.9/unlzh.c.4337 2007-01-15 16:31:53.000000000 +0100
-+++ gzip-1.3.9/unlzh.c 2007-01-15 16:38:08.000000000 +0100
-@@ -146,8 +146,8 @@
- start[1] = 0;
- for (i = 1; i <= 16; i++)
- start[i + 1] = start[i] + (count[i] << (16 - i));
-- if ((start[17] & 0xffff) != 0)
-- gzip_error ("Bad table\n");
-+ if ((start[17] & 0xffff) != 0 || tablebits > 16) /* 16 for weight below */
-+ gzip_error ("Bad table (case b)\n");
-
- jutbits = 16 - tablebits;
- for (i = 1; i <= (unsigned)tablebits; i++) {
-@@ -161,15 +162,15 @@
-
- i = start[tablebits + 1] >> jutbits;
- if (i != 0) {
-- k = 1 << tablebits;
-- while (i != k) table[i++] = 0;
-+ k = MIN(1 << tablebits, DIST_BUFSIZE);
-+ while (i < k) table[i++] = 0;
- }
-
- avail = nchar;
- mask = (unsigned) 1 << (15 - tablebits);
- for (ch = 0; ch < (unsigned)nchar; ch++) {
- if ((len = bitlen[ch]) == 0) continue;
-- nextcode = start[len] + weight[len];
-+ nextcode = MIN(start[len] + weight[len], DIST_BUFSIZE);
- if (len <= (unsigned)tablebits) {
- if ((unsigned) 1 << tablebits < nextcode)
- gzip_error ("Bad table\n");
-@@ -212,7 +213,7 @@
- for (i = 0; i < 256; i++) pt_table[i] = c;
- } else {
- i = 0;
-- while (i < n) {
-+ while (i < MIN(n,NPT)) {
- c = bitbuf >> (BITBUFSIZ - 3);
- if (c == 7) {
- mask = (unsigned) 1 << (BITBUFSIZ - 1 - 3);
-@@ -224,7 +225,7 @@
- pt_len[i++] = c;
- if (i == i_special) {
- c = getbits(2);
-- while (--c >= 0) pt_len[i++] = 0;
-+ while (--c >= 0 && i < NPT) pt_len[i++] = 0;
- }
- }
- while (i < nn) pt_len[i++] = 0;
-@@ -244,7 +245,7 @@
- for (i = 0; i < 4096; i++) c_table[i] = c;
- } else {
- i = 0;
-- while (i < n) {
-+ while (i < MIN(n,NC)) {
- c = pt_table[bitbuf >> (BITBUFSIZ - 8)];
- if (c >= NT) {
- mask = (unsigned) 1 << (BITBUFSIZ - 1 - 8);
-@@ -259,7 +260,7 @@
- if (c == 0) c = 1;
- else if (c == 1) c = getbits(4) + 3;
- else c = getbits(CBIT) + 20;
-- while (--c >= 0) c_len[i++] = 0;
-+ while (--c >= 0 && i < NC) c_len[i++] = 0;
- } else c_len[i++] = c - 2;
- }
- while (i < NC) c_len[i++] = 0;
-@@ -352,7 +353,7 @@
- while (--j >= 0) {
- buffer[r] = buffer[i];
- i = (i + 1) & (DICSIZ - 1);
-- if (++r == count) return r;
-+ if (++r >= count) return r;
- }
- for ( ; ; ) {
- c = decode_c();
-@@ -362,14 +363,14 @@
- }
- if (c <= UCHAR_MAX) {
- buffer[r] = c;
-- if (++r == count) return r;
-+ if (++r >= count) return r;
- } else {
- j = c - (UCHAR_MAX + 1 - THRESHOLD);
- i = (r - decode_p() - 1) & (DICSIZ - 1);
- while (--j >= 0) {
- buffer[r] = buffer[i];
- i = (i + 1) & (DICSIZ - 1);
-- if (++r == count) return r;
-+ if (++r >= count) return r;
- }
- }
- }
---- gzip-1.3.9/gzip.h.4337 2007-01-15 16:31:53.000000000 +0100
-+++ gzip-1.3.9/gzip.h 2007-01-15 16:38:52.000000000 +0100
-@@ -224,6 +224,8 @@
- #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(0))
- #define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
-
-+#define MIN(a,b) ((a) <= (b) ? (a) : (b))
-+
- /* put_byte is used for the compressed output, put_ubyte for the
- * uncompressed output. However unlzw() uses window for its
- * suffix table instead of its output buffer, so it does not use put_ubyte
---- gzip-1.3.9/unpack.c.4337 2007-01-15 16:31:53.000000000 +0100
-+++ gzip-1.3.9/unpack.c 2007-01-15 16:39:12.000000000 +0100
-@@ -21,9 +21,6 @@
- #include "tailor.h"
- #include "gzip.h"
-
--#define MIN(a,b) ((a) <= (b) ? (a) : (b))
--/* The arguments must not have side effects. */
--
- #define MAX_BITLEN 25
- /* Maximum length of Huffman codes. (Minor modifications to the code
- * would be needed to support 32 bits codes, but pack never generates
-
+++ /dev/null
-diff -up gzip-1.3.13/deflate.c.rsync gzip-1.3.13/deflate.c
---- gzip-1.3.13/deflate.c.rsync 2009-09-26 20:43:28.000000000 +0200
-+++ gzip-1.3.13/deflate.c 2009-12-01 16:14:24.656387546 +0100
-@@ -131,6 +131,14 @@
- #endif
- /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
-
-+#ifndef RSYNC_WIN
-+# define RSYNC_WIN 4096
-+#endif
-+/* Size of rsync window, must be < MAX_DIST */
-+
-+#define RSYNC_SUM_MATCH(sum) ((sum) % RSYNC_WIN == 0)
-+/* Whether window sum matches magic value */
-+
- /* ===========================================================================
- * Local data used by the "longest match" routines.
- */
-@@ -212,6 +220,8 @@ local int compr_level;
- unsigned 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
-@@ -310,6 +320,10 @@ void lm_init (pack_level, flags)
- #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;
-@@ -546,6 +560,8 @@ local void fill_window()
- 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;
-
-@@ -573,13 +589,46 @@ local void fill_window()
- }
- }
-
-+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.
- */
- #define FLUSH_BLOCK(eof) \
- flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \
-- (char*)NULL, (long)strstart - block_start, (eof))
-+ (char*)NULL, (long)strstart - block_start, flush-1, (eof))
-
- /* ===========================================================================
- * Processes a new input file and return its compressed length. This
-@@ -590,7 +639,7 @@ local void fill_window()
- local off_t deflate_fast()
- {
- IPos hash_head; /* head of the hash chain */
-- int flush; /* set if current block must be flushed */
-+ int flush; /* set if current block must be flushed, 2=>and padded */
- unsigned match_length = 0; /* length of best match */
-
- prev_length = MIN_MATCH-1;
-@@ -674,7 +674,8 @@
- flush = ct_tally(strstart-match_start, match_length - MIN_MATCH);
-
- 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.
- */
-@@ -703,9 +704,14 @@
- /* No match, output a literal byte */
- Tracevv((stderr,"%c",window[strstart]));
- flush = ct_tally (0, window[strstart]);
-+ RSYNC_ROLL(strstart, 1);
- lookahead--;
- strstart++;
- }
-+ if (rsync && strstart > rsync_chunk_end) {
-+ rsync_chunk_end = 0xFFFFFFFFUL;
-+ flush = 2;
-+ }
- if (flush) FLUSH_BLOCK(0), block_start = strstart;
-
- /* Make sure that we always have enough lookahead, except
-@@ -724,6 +779,7 @@ off_t deflate()
- */
- lookahead -= prev_length-1;
- prev_length -= 2;
-+ RSYNC_ROLL(strstart, prev_length+1);
- do {
- strstart++;
- INSERT_STRING(strstart, hash_head);
-@@ -736,24 +792,40 @@ off_t deflate()
- match_available = 0;
- match_length = MIN_MATCH-1;
- strstart++;
-- if (flush) FLUSH_BLOCK(0), block_start = strstart;
-
-+ if (rsync && strstart > rsync_chunk_end) {
-+ rsync_chunk_end = 0xFFFFFFFFUL;
-+ flush = 2;
-+ }
-+ 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]));
-- 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) {
-+ rsync_chunk_end = 0xFFFFFFFFUL;
-+ flush = 2;
- }
-+ 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.
- */
-+ if (rsync && strstart > rsync_chunk_end) {
-+ /* Reset huffman tree */
-+ rsync_chunk_end = 0xFFFFFFFFUL;
-+ flush = 2;
-+ FLUSH_BLOCK(0), block_start = strstart;
-+ }
-+
- match_available = 1;
-+ RSYNC_ROLL(strstart, 1);
- strstart++;
- lookahead--;
- }
-diff -up gzip-1.3.13/doc/gzip.texi.rsync gzip-1.3.13/doc/gzip.texi
---- gzip-1.3.13/doc/gzip.texi.rsync 2009-09-28 11:08:16.000000000 +0200
-+++ gzip-1.3.13/doc/gzip.texi 2009-12-01 16:14:24.664394713 +0100
-@@ -353,6 +353,14 @@ specified on the command line are direct
- into the directory and compress all the files it finds there (or
- decompress them in the case of @command{gunzip}).
-
-+@item --rsyncable
-+While compressing, synchronize the output occasionally based on the
-+input. This reduces compression by about 1 percent most cases, but
-+means that the @code{rsync} program can take advantage of similarities
-+in the uncompressed input when syncronizing two files compressed with
-+this flag. @code{gunzip} cannot tell the difference between a
-+compressed file created with this option, and one created without it.
-+
- @item --suffix @var{suf}
- @itemx -S @var{suf}
- Use suffix @var{suf} instead of @samp{.gz}. Any suffix can be
-diff -up gzip-1.3.13/gzip.c.rsync gzip-1.3.13/gzip.c
---- gzip-1.3.13/gzip.c.rsync 2009-09-26 20:56:02.000000000 +0200
-+++ gzip-1.3.13/gzip.c 2009-12-01 16:18:17.121387126 +0100
-@@ -229,6 +229,7 @@ int ofd; /* output fil
- unsigned insize; /* valid bytes in inbuf */
- unsigned inptr; /* index of next byte to be processed in inbuf */
- unsigned outcnt; /* bytes in output buffer */
-+int rsync = 0; /* make ryncable chunks */
-
- static int handled_sig[] =
- {
-@@ -271,7 +271,7 @@ static const struct option longopts[] =
- {"best", 0, 0, '9'}, /* compress better */
- {"lzw", 0, 0, 'Z'}, /* make output compatible with old compress */
- {"bits", 1, 0, 'b'}, /* max number of bits per code (implies -Z) */
--
-+ {"rsyncable", 0, 0, 'R'}, /* make rsync-friendly archive */
- { 0, 0, 0, 0 }
- };
-
-
-@@ -363,6 +365,7 @@ local void help()
- " -Z, --lzw produce output compatible with old compress",
- " -b, --bits=BITS max number of bits per code (implies -Z)",
- #endif
-+ " --rsyncable Make rsync-friendly archive",
- "",
- "With no FILE, or when FILE is -, read standard input.",
- "",
-@@ -484,6 +484,9 @@ int main (int argc, char **argv)
- recursive = 1;
- #endif
- break;
-+
-+ case 'R':
-+ rsync = 1; break;
- case 'S':
- #ifdef NO_MULTIPLE_DOTS
- if (*optarg == '.') optarg++;
-
-diff -up gzip-1.3.13/gzip.h.rsync gzip-1.3.13/gzip.h
---- gzip-1.3.13/gzip.h.rsync 2009-09-26 20:43:28.000000000 +0200
-+++ gzip-1.3.13/gzip.h 2009-12-01 16:14:24.664394713 +0100
-@@ -158,6 +158,7 @@ EXTERN(uch, window); /* Sliding
- extern unsigned insize; /* valid bytes in inbuf */
- extern unsigned inptr; /* index of next byte to be processed in inbuf */
- extern unsigned outcnt; /* bytes in output buffer */
-+extern int rsync; /* deflate into rsyncable chunks */
-
- extern off_t bytes_in; /* number of input bytes */
- extern off_t bytes_out; /* number of output bytes */
-@@ -288,7 +288,7 @@ extern off_t deflate (void);
- /* in trees.c */
- extern void ct_init (ush *attr, int *method);
- extern int ct_tally (int dist, int lc);
--extern off_t flush_block (char *buf, ulg stored_len, int eof);
-+extern off_t flush_block (char *buf, ulg stored_len, int pad, int eof);
-
- /* in bits.c */
- extern void bi_init (file_t zipfile);
-
-diff -up gzip-1.3.13/trees.c.rsync gzip-1.3.13/trees.c
---- gzip-1.3.13/trees.c.rsync 2009-09-26 20:43:28.000000000 +0200
-+++ gzip-1.3.13/trees.c 2009-12-01 16:14:24.655388257 +0100
-@@ -856,9 +856,10 @@ local void send_all_trees(lcodes, dcodes
- * trees or store, and output the encoded block to the zip file. This function
- * returns the total compressed length for the file so far.
- */
--off_t flush_block(buf, stored_len, eof)
-+off_t flush_block(buf, stored_len, pad, eof)
- char *buf; /* input block, or NULL if too old */
- ulg stored_len; /* length of input block */
-+ int pad; /* pad output to byte boundary */
- int eof; /* true if this is the last block for a file */
- {
- ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
-@@ -951,6 +952,10 @@ off_t flush_block(buf, stored_len, eof)
- Assert (input_len == bytes_in, "bad input size");
- bi_windup();
- compressed_len += 7; /* align on byte boundary */
-+ } else if (pad && (compressed_len % 8) != 0) {
-+ send_bits((STORED_BLOCK<<1)+eof, 3); /* send block type */
-+ compressed_len = (compressed_len + 3 + 7) & ~7L;
-+ copy_block(buf, 0, 1); /* with header */
- }
-
- return compressed_len >> 3;