--- mod_gzip.c-old	Fri Jan 26 10:50:05 2001
+++ mod_gzip.c	Fri Jan 26 15:08:26 2001
@@ -575,10 +575,15 @@
  * The GZP request control structure...
  */
 
+#define GZIP_FORMAT    (0)
+#define DEFLATE_FORMAT (1)
+
 typedef struct _GZP_CONTROL {
 
     int   decompress;  /* 0=Compress 1=Decompress */
 
+    int   compression_format;  /* GZIP_FORMAT or DEFLATE_FORMAT */
+
     /* Input control... */
 
     int   input_ismem;         /* Input source is memory buffer, not file */
@@ -2209,10 +2214,11 @@
        mod_gzip_printf( "%s: Checking for 'gzip' designator...\n",cn);
        #endif
 
-       if ( strstr( has_encoding, "gzip" ) )
+       if ( strstr( has_encoding, "gzip" ) ||
+			strstr( has_encoding, "deflate" ) )
          {
           #ifdef MOD_GZIP_DEBUG1
-          mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' designator...\n",cn);
+          mod_gzip_printf( "%s: 'Content-encoding:' field contains 'gzip' or 'deflate' designator...\n",cn);
           mod_gzip_printf( "%s: Pre-compression is assumed.\n",cn);
           mod_gzip_printf( "%s: Exit > return( DECLINED ) >\n",cn);
           #endif
@@ -2237,7 +2243,7 @@
        else /* 'gzip' designator not found... */
          {
           #ifdef MOD_GZIP_DEBUG1
-          mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' designator...\n",cn);
+          mod_gzip_printf( "%s: 'Content-encoding:' field does NOT contain 'gzip' or 'deflate' designator...\n",cn);
           mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
           #endif
          }
@@ -2347,10 +2353,21 @@
     if ( accept_encoding )
       {
        /* ...and if it has the right 'gzip' indicator... */
-
+	   /* We record the compression format in a request note, so we
+        * can get it again later, and so it can potentially be logged.
+        */
        if ( strstr( accept_encoding, "gzip" ) )
          {
           process = 1; /* ...set the 'process' flag TRUE */
+          ap_table_setn( r->notes,"mod_gzip_compression_format",
+						 ap_pstrdup(r->pool,"gzip"));
+
+         }
+       else if ( strstr( accept_encoding, "deflate" ) )
+         {
+          process = 1; /* ...set the 'process' flag TRUE */
+          ap_table_setn( r->notes,"mod_gzip_compression_format",
+						 ap_pstrdup(r->pool,"deflate"));
          }
 
       }/* End 'if( accept_encoding )' */
@@ -2388,7 +2405,7 @@
     else /* 'gzip' designator was seen in 'Accept-Encoding:' field */
       {
        #ifdef MOD_GZIP_DEBUG1
-       mod_gzip_printf( "%s: 'gzip' capability specified by user-agent.\n",cn);
+       mod_gzip_printf( "%s: 'gzip' or 'deflate' capability specified by user-agent.\n",cn);
        mod_gzip_printf( "%s: Assuming OK to proceed...\n",cn);
        #endif
       }
@@ -4093,7 +4110,8 @@
 
     char tmp[ MOD_GZIP_LARGE_BUFFER_SIZE + 2 ]; /* Scratch buffer */
 
-    char actual_content_encoding_name[] = "gzip"; /* Adjustable */
+    char *actual_content_encoding_name = "gzip"; /* Adjustable */
+	const char *compression_format;
 
     #ifdef MOD_GZIP_DEBUG1
     char cn[]="mod_gzip_encode_and_transmit()";
@@ -4470,6 +4488,18 @@
 
     gzp->decompress = 0; /* Perform encoding */
 
+	/* Recover the compression format we're supposed to use. */
+	compression_format = ap_table_get(r->notes, "mod_gzip_compression_format");
+	if (compression_format && strcmp(compression_format, "deflate") == 0)
+	  {
+	   actual_content_encoding_name = "deflate";
+	   gzp->compression_format = DEFLATE_FORMAT;
+      }
+    else
+	  {
+	   gzp->compression_format = GZIP_FORMAT;
+      }
+
     if ( input_size <= (long) conf->maximum_inmem_size )
       {
        /* The input source is small enough to compress directly */
@@ -4591,6 +4621,7 @@
 
     #ifdef MOD_GZIP_DEBUG1
     mod_gzip_printf( "%s: gzp->decompress      = %d\n"  ,cn,gzp->decompress);
+    mod_gzip_printf( "%s: gzp->compression_format = %d\n",cn,gzp->compression_format);
     mod_gzip_printf( "%s: gzp->input_ismem     = %d\n",  cn,gzp->input_ismem);
     mod_gzip_printf( "%s: gzp->output_ismem    = %d\n",  cn,gzp->output_ismem);
     mod_gzip_printf( "%s: gzp->input_filename  = [%s]\n",cn,gzp->input_filename);
@@ -7256,6 +7287,8 @@
 };
 
 typedef struct _GZ1 {
+ long     compression_format;
+
  long     versionid1;
  int      state;
  int      done;
@@ -7345,6 +7378,7 @@
  int  dbits;            
  ulg  window_size;      
  ulg  crc;              
+ ulg  adler;
 
  uch  dist_code[512];
  uch  length_code[MAX_MATCH-MIN_MATCH+1];
@@ -7449,6 +7483,15 @@
 
 void  error( char *msg   );
 
+/* XXX - Precomputed zlib header. If you change the window size or
+ * compression level from the defaults, this will break badly. The
+ * algorithm to build this is fairly complex; you can find it in
+ * the file deflate.c from the zlib distribution.
+ */
+#define ZLIB_HEADER "\170�"
+
+ulg adler32(ulg adler, uch *buf, unsigned len);
+
 int zip(
 PGZ1 gz1, 
 int  in,  
@@ -9088,10 +9131,20 @@
  if ( len == (unsigned)(-1) || len == 0 )
    {
 	gz1->crc = gz1->crc ^ 0xffffffffL;
+    /* XXX - Do we need to do something with Adler CRC's here?
+	 * I don't think so--they don't seem to need postprocessing. */
     return (int)len;
    }
 
- updcrc( gz1, (uch*)buf, len );
+ if (gz1->compression_format != DEFLATE_FORMAT)
+   {
+    updcrc( gz1, (uch*)buf, len );
+   }
+ else
+   {
+	gz1->adler = adler32(gz1->adler, (uch*)buf, len);
+   }
+
  gz1->bytes_in += (ulg)len;
 
  return (int)len;
@@ -9288,6 +9341,7 @@
  gz1->heap[k] = v;
 }
 
+
 #define GZS_ZIP1      1
 #define GZS_ZIP2      2
 #define GZS_DEFLATE1  3
@@ -9317,6 +9371,7 @@
    }
 
  gz1->decompress      = gzp->decompress;
+ gz1->compression_format = gzp->compression_format;
 
  strcpy( gz1->ifname, gzp->input_filename  );
  strcpy( gz1->ofname, gzp->output_filename );
@@ -9489,6 +9544,7 @@
  return( rc );
 }
 
+
 int gzs_zip1( PGZ1 gz1 )
 {
  uch  flags = 0;         
@@ -9499,21 +9555,40 @@
 
  gz1->method = DEFLATED;
 
- put_byte(GZIP_MAGIC[0]); 
- put_byte(GZIP_MAGIC[1]);
- put_byte(DEFLATED);      
+ if (gz1->compression_format != DEFLATE_FORMAT)
+   {
+    put_byte(GZIP_MAGIC[0]); 
+    put_byte(GZIP_MAGIC[1]);
+    put_byte(DEFLATED);      
+   }
+ else
+   {
+	/* Yes, I know RFC 1951 doesn't mention any header at the start of
+	 * a deflated document, but zlib absolutely requires one. And since nearly
+     * all "deflate" implementations use zlib, we need to play along with this
+     * brain damage. */
+    put_byte(ZLIB_HEADER[0]); 
+    put_byte(ZLIB_HEADER[1]);
+   }
 
  if ( gz1->save_orig_name )
    {
 	flags |= ORIG_NAME;
    }
 
- put_byte(flags);           
- put_long(gz1->time_stamp); 
-
- gz1->crc = -1; 
+ if (gz1->compression_format != DEFLATE_FORMAT)
+   {
+    put_byte(flags);           
+    put_long(gz1->time_stamp); 
 
- updcrc( gz1, NULL, 0 ); 
+	gz1->crc = -1; 
+    updcrc( gz1, NULL, 0 ); 
+   }
+ else
+   {
+	/* Deflate compression uses an Adler32 CRC, not a CRC32. */
+	gz1->adler = 1L;
+   }
 
  gz1->state = GZS_ZIP2;
 
@@ -9529,18 +9604,20 @@
  bi_init( gz1, gz1->ofd );
  ct_init( gz1, &attr, &gz1->method );
  lm_init( gz1, gz1->level, &deflate_flags );
- put_byte((uch)deflate_flags); 
-
- put_byte(OS_CODE); 
 
- if ( gz1->save_orig_name )
+ if (gz1->compression_format != DEFLATE_FORMAT)
    {
-    char *p = gz1_basename( gz1, gz1->ifname );
+    put_byte((uch)deflate_flags); 
+    put_byte(OS_CODE); 
+    if ( gz1->save_orig_name )
+      {
+       char *p = gz1_basename( gz1, gz1->ifname );
 
-    do {
-	    put_char(*p);
+       do {
+	       put_char(*p);
 
-       } while (*p++);
+          } while (*p++);
+      }
    }
 
  gz1->header_bytes = (long)gz1->outcnt;
@@ -9674,10 +9751,25 @@
    }
  #endif
 
- put_long( gz1->crc      );
- put_long( gz1->bytes_in );
-
- gz1->header_bytes += 2*sizeof(long);
+ if (gz1->compression_format != DEFLATE_FORMAT)
+   {
+    put_long( gz1->crc );
+    put_long( gz1->bytes_in );
+    gz1->header_bytes += 2*sizeof(long);
+   }
+ else
+   {
+	/* Append an Adler32 CRC to our deflated data.
+	 * Yes, I know RFC 1951 doesn't mention any CRC at the end of a
+	 * deflated document, but zlib absolutely requires one. And since nearly
+	 * all "deflate" implementations use zlib, we need to play along with this
+	 * brain damage. */
+	put_byte( (gz1->adler >> 24)        );
+	put_byte( (gz1->adler >> 16) & 0xFF );
+	put_byte( (gz1->adler >>  8) & 0xFF );
+	put_byte( (gz1->adler      ) & 0xFF );
+    gz1->header_bytes += 4*sizeof(uch);
+   }
 
  flush_outbuf( gz1 );
 
@@ -9685,6 +9777,67 @@
 
  return OK;
 }
+
+
+/* =========================================================================
+   adler32 -- compute the Adler-32 checksum of a data stream
+   Copyright (C) 1995-1998 Mark Adler
+
+   This software is provided 'as-is', without any express or implied
+   warranty.  In no event will the authors be held liable for any damages
+   arising from the use of this software.
+
+   Permission is granted to anyone to use this software for any purpose,
+   including commercial applications, and to alter it and redistribute it
+   freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+      claim that you wrote the original software. If you use this software
+      in a product, an acknowledgment in the product documentation would be
+      appreciated but is not required.
+   2. Altered source versions must be plainly marked as such, and must not be
+      misrepresented as being the original software.
+   3. This notice may not be removed or altered from any source distribution.
+
+   Modified by Eric Kidd <eric.kidd@pobox.com> to play nicely with mod_gzip.
+ */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+ulg adler32(ulg adler, uch *buf, unsigned len)
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+
 
 /* END OF FILE */