From fb221562a3c2e6874a48cfcdae29ff1fd1457eb9 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 29 Apr 1997 15:38:09 +0000 Subject: [PATCH] Added Andrew Kuchling's zlib module. --- Modules/zlibmodule.c | 670 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 670 insertions(+) create mode 100644 Modules/zlibmodule.c diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c new file mode 100644 index 00000000000..6fe97292fe4 --- /dev/null +++ b/Modules/zlibmodule.c @@ -0,0 +1,670 @@ +/* zlibmodule.c -- gzip-compatible data compression */ + +#include +#include + +/* 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"); +}