Added Andrew Kuchling's zlib module.
diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
new file mode 100644
index 0000000..6fe9729
--- /dev/null
+++ b/Modules/zlibmodule.c
@@ -0,0 +1,670 @@
+/* zlibmodule.c -- gzip-compatible data compression */
+
+#include <Python.h>
+#include <zlib.h>
+
+/* The following parameters are copied from zutil.h, version 0.95 */
+#define DEFLATED   8
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+#define DEF_WBITS MAX_WBITS
+
+/* The output buffer will be increased in chunks of ADDCHUNK bytes. */
+#define ADDCHUNK 2048
+#define PyInit_zlib initzlib
+
+staticforward PyTypeObject Comptype;
+staticforward PyTypeObject Decomptype;
+
+static PyObject *ZlibError;
+
+typedef struct 
+{
+  PyObject_HEAD
+  z_stream zst;
+} compobject;
+
+static compobject *
+newcompobject(type)
+     PyTypeObject *type;
+{
+        compobject *self;
+        self = PyObject_NEW(compobject, type);
+        if (self == NULL)
+                return NULL;
+        return self;
+}
+
+static PyObject *
+PyZlib_compress(self, args)
+        PyObject *self;
+        PyObject *args;
+{
+  PyObject *ReturnVal;
+  Byte *input, *output;
+  int length, level=Z_DEFAULT_COMPRESSION, err;
+  z_stream zst;
+  
+  if (!PyArg_ParseTuple(args, "s#|i", &input, &length, &level))
+    return NULL;
+  zst.avail_out=length+length/1000+12+1;
+  output=(Byte*)malloc(zst.avail_out);
+  if (output==NULL) 
+    {
+      PyErr_SetString(PyExc_MemoryError,
+                      "Can't allocate memory to compress data");
+      return NULL;
+    }
+  zst.zalloc=(alloc_func)zst.zfree=(free_func)Z_NULL;
+  zst.next_out=(Byte *)output;
+  zst.next_in =(Byte *)input;
+  zst.avail_in=length;
+  err=deflateInit(&zst, level);
+  switch(err) 
+    {
+    case(Z_OK):
+      break;
+    case(Z_MEM_ERROR):
+      PyErr_SetString(PyExc_MemoryError,
+                      "Out of memory while compressing data");
+      free(output);
+      return NULL;
+      break;
+    case(Z_STREAM_ERROR):
+      PyErr_SetString(ZlibError,
+                      "Bad compression level");
+      free(output);
+      return NULL;
+      break;
+    default:
+      {
+        char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+        sprintf(temp, "Error %i while compressing data [%s]", err, zst.msg);
+        PyErr_SetString(ZlibError, temp);
+        deflateEnd(&zst);
+        free(output);
+        return NULL;
+      }
+      break;
+    }
+ 
+  err=deflate(&zst, Z_FINISH);
+  switch(err)
+    {
+    case(Z_STREAM_END):
+      break;
+      /* Are there other errors to be trapped here? */
+    default: 
+      {
+         char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+         sprintf(temp, "Error %i while compressing data [%s]", err, zst.msg);
+         PyErr_SetString(ZlibError, temp);
+         deflateEnd(&zst);
+         free(output);
+         return NULL;
+       }
+     }
+  err=deflateEnd(&zst);
+  if (err!=Z_OK) 
+    {
+      char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+      sprintf(temp, "Error %i while finishing data compression [%s]",
+              err, zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      free(output);
+      return NULL;
+    }
+  ReturnVal=PyString_FromStringAndSize(output, zst.total_out);
+  free(output);
+  return ReturnVal;
+}
+
+static PyObject *
+PyZlib_decompress(self, args)
+        PyObject *self;
+        PyObject *args;
+{
+  PyObject *ReturnVal;
+  Byte *input, *output;
+  int length, err;
+  z_stream zst;
+  if (!PyArg_ParseTuple(args, "s#", &input, &length))
+    return NULL;
+  
+  zst.avail_in=length;
+  zst.avail_out=length=length*2;
+  output=(Byte*)malloc(zst.avail_out);
+  if (output==NULL) 
+    {
+      PyErr_SetString(PyExc_MemoryError,
+                      "Can't allocate memory to decompress data");
+      return NULL;
+    }
+  zst.zalloc=(alloc_func)zst.zfree=(free_func)Z_NULL;
+  zst.next_out=(Byte *)output;
+  zst.next_in =(Byte *)input;
+  err=inflateInit(&zst);
+  switch(err)
+    {
+    case(Z_OK):
+      break;
+    case(Z_MEM_ERROR):      
+      PyErr_SetString(PyExc_MemoryError,
+                      "Out of memory while decompressing data");
+      free(output);
+      return NULL;
+    default:
+      {
+        char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+        sprintf(temp, "Error %i while preparing to decompress data [%s]",
+                err, zst.msg);
+        PyErr_SetString(ZlibError, temp);
+        inflateEnd(&zst);
+        free(output);
+        return NULL;
+      }
+    }
+  do 
+    {
+      err=inflate(&zst, Z_FINISH);
+      switch(err) 
+        {
+        case(Z_OK):
+        case(Z_STREAM_END):
+          output=(Byte *)realloc(output, length+ADDCHUNK);
+          if (output==NULL) 
+            {
+              PyErr_SetString(PyExc_MemoryError,
+                              "Out of memory while decompressing data");
+              inflateEnd(&zst);
+              return NULL;
+            }
+          zst.next_out=output+length;
+          zst.avail_out=ADDCHUNK;
+          length += ADDCHUNK;
+          break;
+        default:
+          {
+            char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+            sprintf(temp, "Error %i while decompressing data: [%s]",
+                    err, zst.msg);
+            PyErr_SetString(ZlibError, temp);
+            inflateEnd(&zst);
+            return NULL;
+          }
+        }
+    } while(err!=Z_STREAM_END);
+  
+  err=inflateEnd(&zst);
+  if (err!=Z_OK) 
+    {
+      char temp[500];
+	if (zst.msg==Z_NULL) zst.msg="";
+      sprintf(temp, "Error %i while finishing data decompression [%s]",
+              err, zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      free(output);
+      return NULL;
+    }
+  ReturnVal=PyString_FromStringAndSize(output, zst.total_out);
+  free(output);
+  return ReturnVal;
+}
+
+static PyObject *
+PyZlib_compressobj(selfptr, args)
+        PyObject *selfptr;
+        PyObject *args;
+{
+  compobject *self;
+  int level=Z_DEFAULT_COMPRESSION, method=DEFLATED;
+  int wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=0, err;
+  /* XXX Argh!  Is there a better way to have multiple levels of */
+  /* optional arguments? */
+  if (!PyArg_ParseTuple(args, "iiiii", &level, &method, &wbits, &memLevel, &strategy))
+    {
+     PyErr_Clear();
+     if (!PyArg_ParseTuple(args, "iiii", &level, &method, &wbits,
+			   &memLevel))
+       {     
+	PyErr_Clear();
+	if (!PyArg_ParseTuple(args, "iii", &level, &method, &wbits))
+	  {
+	   PyErr_Clear();
+	   if (!PyArg_ParseTuple(args, "ii", &level, &method))
+	     {
+	      PyErr_Clear();
+	      if (!PyArg_ParseTuple(args, "i", &level))
+		{
+		 PyErr_Clear();
+		 if (!PyArg_ParseTuple(args, ""))
+		   return (NULL);
+		}
+	     }
+	  }
+       }
+    }
+  self=newcompobject(&Comptype);
+  if (self==NULL) return(NULL);
+  self->zst.zalloc=(alloc_func)self->zst.zfree=(free_func)Z_NULL;
+  err=deflateInit2(&self->zst, level, method, wbits, memLevel, strategy);
+  switch(err)
+    {
+    case (Z_OK):
+      return (PyObject*)self;
+      break;
+    case (Z_MEM_ERROR):
+      PyErr_SetString(PyExc_MemoryError,
+                      "Can't allocate memory for compression object");
+      return NULL;
+      break;
+    case(Z_STREAM_ERROR):
+      PyErr_SetString(PyExc_ValueError,
+                      "Invalid compression level");
+      return NULL;
+      break;
+    default:
+      {
+	char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+        sprintf(temp, "Error %i while creating compression object [%s]",
+		err, self->zst.msg);
+	PyErr_SetString(ZlibError, temp);
+	return NULL;
+	break;      
+      }
+    }
+}
+
+static PyObject *
+PyZlib_decompressobj(selfptr, args)
+        PyObject *selfptr;
+        PyObject *args;
+{
+  int wbits=DEF_WBITS, err;
+  compobject *self;
+  if (!PyArg_ParseTuple(args, "|i", &wbits))
+    {
+     return NULL;
+    }  
+  self=newcompobject(&Decomptype);
+  if (self==NULL) return(NULL);
+  self->zst.zalloc=(alloc_func)self->zst.zfree=(free_func)Z_NULL;
+  /* XXX If illegal values of wbits are allowed to get here, Python
+     coredumps, instead of raising an exception as it should. 
+     This is a bug in zlib 0.95; I have reported it. */
+  err=inflateInit2(&self->zst, wbits);
+  switch(err)
+    {
+    case (Z_OK):
+      return (PyObject*)self;
+      break;
+    case (Z_MEM_ERROR):
+      PyErr_SetString(PyExc_MemoryError,
+                      "Can't allocate memory for decompression object");
+      return NULL;
+      break;
+    default:
+      {
+	char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+        sprintf(temp, "Error %i while creating decompression object [%s]",
+		err, self->zst.msg);	
+	PyErr_SetString(ZlibError, temp);
+	return NULL;
+	break;      
+      }
+    }
+}
+
+static void
+Comp_dealloc(self)
+        compobject *self;
+{
+  int err;
+  err=deflateEnd(&self->zst);  /* Deallocate zstream structure */
+}
+
+static void
+Decomp_dealloc(self)
+        compobject *self;
+{
+  int err;
+  err=inflateEnd(&self->zst);	/* Deallocate zstream structure */
+}
+
+static PyObject *
+PyZlib_objcompress(self, args)
+        compobject *self;
+        PyObject *args;
+{
+  int length=0, err, inplen;
+  Byte *buf=NULL;
+  PyObject *RetVal;
+  Byte *input;
+  
+  if (!PyArg_ParseTuple(args, "s#", &input, &inplen))
+    return NULL;
+  self->zst.avail_in=inplen;
+  self->zst.next_in=input;
+  do 
+    {
+      buf=(Byte *)realloc(buf, length+ADDCHUNK);
+      if (buf==NULL) 
+	{
+	  PyErr_SetString(PyExc_MemoryError,
+			  "Can't allocate memory to compress data");
+	  return NULL;
+	}
+      self->zst.next_out=buf+length;
+      self->zst.avail_out=ADDCHUNK;
+      length += ADDCHUNK;
+      err=deflate(&(self->zst), Z_NO_FLUSH);
+    } while (self->zst.avail_in!=0 && err==Z_OK);
+  if (err!=Z_OK) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while compressing [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  RetVal=PyString_FromStringAndSize(buf, self->zst.next_out-buf);
+  free(buf);
+  return RetVal;
+}
+
+static PyObject *
+PyZlib_objdecompress(self, args)
+        compobject *self;
+        PyObject *args;
+{
+  int length=0, err, inplen;
+  Byte *buf=NULL;
+  PyObject *RetVal;
+  Byte *input;
+  if (!PyArg_ParseTuple(args, "s#", &input, &inplen))
+    return NULL;
+  self->zst.avail_in=inplen;
+  self->zst.next_in=input;
+  do 
+    {
+      buf=(Byte *)realloc(buf, length+ADDCHUNK);
+      if (buf==NULL) 
+	{
+	  PyErr_SetString(PyExc_MemoryError,
+			  "Can't allocate memory to decompress data");
+	  return NULL;
+	}
+      self->zst.next_out=buf+length;
+      self->zst.avail_out=ADDCHUNK;
+      length += ADDCHUNK;
+      err=inflate(&(self->zst), Z_NO_FLUSH);
+    } while (self->zst.avail_in!=0 && err==Z_OK);
+  if (err!=Z_OK && err!=Z_STREAM_END) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while decompressing [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  RetVal=PyString_FromStringAndSize(buf, self->zst.next_out-buf);
+  free(buf);
+  return RetVal;
+}
+
+static PyObject *
+PyZlib_flush(self, args)
+        compobject *self;
+        PyObject *args;
+{
+  int length=0, err;
+  Byte *buf=NULL;
+  PyObject *RetVal;
+  
+  if (!PyArg_NoArgs(args))
+    return NULL;
+  self->zst.avail_in=0;
+  do 
+    {
+      buf=(Byte *)realloc(buf, length+ADDCHUNK);
+      if (buf==NULL) 
+	{
+	  PyErr_SetString(PyExc_MemoryError,
+			  "Can't allocate memory to compress data");
+	  return NULL;
+	}
+      self->zst.next_out=buf+length;
+      self->zst.avail_out=ADDCHUNK;
+      length += ADDCHUNK;
+      err=deflate(&(self->zst), Z_FINISH);
+    } while (err==Z_OK);
+  if (err!=Z_STREAM_END) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while compressing [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  RetVal=PyString_FromStringAndSize(buf, self->zst.next_out-buf);
+  free(buf);
+  err=deflateEnd(&(self->zst));
+  if (err!=Z_OK) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while flushing compression object [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  return RetVal;
+}
+
+static PyObject *
+PyZlib_unflush(self, args)
+        compobject *self;
+        PyObject *args;
+{
+  int length=0, err;
+  Byte *buf=NULL;
+  PyObject *RetVal;
+  
+  if (!PyArg_NoArgs(args))
+    return NULL;
+  self->zst.avail_in=0;
+  do 
+    {
+      buf=(Byte *)realloc(buf, length+ADDCHUNK);
+      if (buf==NULL) 
+	{
+	  PyErr_SetString(PyExc_MemoryError,
+			  "Can't allocate memory to decompress data");
+	  return NULL;
+	}
+      self->zst.next_out=buf+length;
+      length += ADDCHUNK;
+      err=inflate(&(self->zst), Z_FINISH);
+    } while (err==Z_OK);
+  if (err!=Z_STREAM_END) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while decompressing [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  RetVal=PyString_FromStringAndSize(buf, self->zst.next_out - buf);
+  free(buf);
+  err=inflateEnd(&(self->zst));
+  if (err!=Z_OK) 
+    {
+      char temp[500];
+	if (self->zst.msg==Z_NULL) self->zst.msg="";
+      sprintf(temp, "Error %i while flushing decompression object [%s]",
+	      err, self->zst.msg);
+      PyErr_SetString(ZlibError, temp);
+      return NULL;
+    }
+  return RetVal;
+}
+
+static PyMethodDef comp_methods[] =
+{
+        {"compress", PyZlib_objcompress, 1},
+        {"flush", PyZlib_flush, 0},
+        {NULL, NULL}
+};
+
+static PyMethodDef Decomp_methods[] =
+{
+        {"decompress", PyZlib_objdecompress, 1},
+        {"flush", PyZlib_unflush, 0},
+        {NULL, NULL}
+};
+
+static PyObject *
+Comp_getattr(self, name)
+     compobject *self;
+     char *name;
+{
+        return Py_FindMethod(comp_methods, (PyObject *)self, name);
+}
+
+static PyObject *
+Decomp_getattr(self, name)
+     compobject *self;
+     char *name;
+{
+        return Py_FindMethod(Decomp_methods, (PyObject *)self, name);
+}
+
+static PyObject *
+PyZlib_adler32(self, args)
+     PyObject *self, *args;
+{
+ uLong adler32val=adler32(0L, Z_NULL, 0);
+ Byte *buf;
+ int len;
+ 
+ if (!PyArg_ParseTuple(args, "s#|l", &buf, &len, &adler32val))
+   {
+    return NULL;
+   }
+ adler32val=adler32(adler32val, buf, len);
+ return Py_BuildValue("l", adler32val);
+}
+     
+
+static PyObject *
+PyZlib_crc32(self, args)
+     PyObject *self, *args;
+{
+ uLong crc32val=crc32(0L, Z_NULL, 0);
+ Byte *buf;
+ int len;
+ if (!PyArg_ParseTuple(args, "s#|l", &buf, &len, &crc32val))
+   {
+    return NULL;
+   }
+ crc32val=crc32(crc32val, buf, len);
+ return Py_BuildValue("l", crc32val);
+}
+     
+
+static PyMethodDef zlib_methods[] =
+{
+	{"adler32", PyZlib_adler32, 1},	 
+        {"compress", PyZlib_compress, 1},
+        {"compressobj", PyZlib_compressobj, 1},
+	{"crc32", PyZlib_crc32, 1},	 
+        {"decompress", PyZlib_decompress, 1},
+        {"decompressobj", PyZlib_decompressobj, 1},
+        {NULL, NULL}
+};
+
+statichere PyTypeObject Comptype = {
+        PyObject_HEAD_INIT(&PyType_Type)
+        0,
+        "Compress",
+        sizeof(compobject),
+        0,
+        (destructor)Comp_dealloc,       /*tp_dealloc*/
+        0,                              /*tp_print*/
+        (getattrfunc)Comp_getattr,      /*tp_getattr*/
+        0,                              /*tp_setattr*/
+        0,                              /*tp_compare*/
+        0,                              /*tp_repr*/
+        0,                              /*tp_as_number*/
+        0,                              /*tp_as_sequence*/
+        0,                              /*tp_as_mapping*/
+};
+
+statichere PyTypeObject Decomptype = {
+        PyObject_HEAD_INIT(&PyType_Type)
+        0,
+        "Decompress",
+        sizeof(compobject),
+        0,
+        (destructor)Decomp_dealloc,     /*tp_dealloc*/
+        0,                              /*tp_print*/
+        (getattrfunc)Decomp_getattr,    /*tp_getattr*/
+        0,                              /*tp_setattr*/
+        0,                              /*tp_compare*/
+        0,                              /*tp_repr*/
+        0,                              /*tp_as_number*/
+        0,                              /*tp_as_sequence*/
+        0,                              /*tp_as_mapping*/
+};
+
+/* The following insint() routine was blatantly ripped off from 
+   socketmodule.c */ 
+
+/* Convenience routine to export an integer value.
+   For simplicity, errors (which are unlikely anyway) are ignored. */
+static void
+insint(d, name, value)
+     PyObject *d;
+     char *name;
+     int value;
+{
+	PyObject *v = PyInt_FromLong((long) value);
+	if (v == NULL) {
+		/* Don't bother reporting this error */
+		PyErr_Clear();
+	}
+	else {
+		PyDict_SetItemString(d, name, v);
+		Py_DECREF(v);
+	}
+}
+
+void
+PyInit_zlib()
+{
+        PyObject *m, *d;
+        m = Py_InitModule("zlib", zlib_methods);
+        d = PyModule_GetDict(m);
+        ZlibError = Py_BuildValue("s", "zlib.error");
+        PyDict_SetItemString(d, "error", ZlibError);
+	insint(d, "MAX_WBITS", MAX_WBITS);
+	insint(d, "DEFLATED", DEFLATED);
+	insint(d, "DEF_MEM_LEVEL", DEF_MEM_LEVEL);
+	
+        if (PyErr_Occurred())
+                Py_FatalError("can't initialize module zlib");
+}