Skip to main content

Modules/zlibmodule.c (part 2)

Source:

cpython 3.14 @ ab2d84fe1023/Modules/zlibmodule.c

This annotation covers the stateful compressor/decompressor objects. See modules_zlib_detail for zlib.compress, zlib.decompress, adler32, and crc32.

Map

LinesSymbolRole
1-100zlib.compressobjCreate a stateful Compress object
101-280Compress.compressFeed data, return compressed bytes so far
281-420Compress.flushFinish the stream; return remaining compressed bytes
421-600zlib.decompressobjCreate a stateful Decompress object
601-780Decompress.decompressFeed compressed data, return decompressed bytes
781-900Decompress.flush / Compress.copyFlush decompressor; clone compressor state

Reading

zlib.compressobj

// CPython: Modules/zlibmodule.c:340 zlib_compressobj_impl
static PyObject *
zlib_compressobj_impl(PyObject *module, int level, int method, int wbits,
int memLevel, int strategy, Py_buffer *zdict)
{
/* Wraps deflateInit2(). wbits controls format:
8..15 = zlib (.compress/.decompress),
24..31 = gzip,
-8..-15 = raw deflate (no header). */
compobject *self = newcompobject(&Comptype);
int err = deflateInit2(&self->zst, level, method, wbits, memLevel, strategy);
if (zdict->len > 0)
deflateSetDictionary(&self->zst, zdict->buf, zdict->len);
return (PyObject *)self;
}

wbits=15 (default) produces zlib-wrapped deflate. wbits=31 produces gzip. wbits=-15 produces raw deflate with no wrapper (used by zipfile).

Compress.compress

// CPython: Modules/zlibmodule.c:480 zlib_Compress_compress_impl
static PyObject *
zlib_Compress_compress_impl(compobject *self, Py_buffer *data)
{
/* Feed data into the compressor; may produce no output (buffered internally). */
self->zst.next_in = data->buf;
self->zst.avail_in = data->len;
do {
self->zst.next_out = obuf;
self->zst.avail_out = DEFAULTALLOC;
err = deflate(&self->zst, Z_NO_FLUSH);
/* append obuf to result */
} while (self->zst.avail_out == 0); /* more output available */
return result;
}

deflate with Z_NO_FLUSH may buffer data internally. Output is only guaranteed after Z_SYNC_FLUSH or Z_FINISH.

Compress.flush

// CPython: Modules/zlibmodule.c:560 zlib_Compress_flush_impl
static PyObject *
zlib_Compress_flush_impl(compobject *self, int mode)
{
/* mode: Z_SYNC_FLUSH (flush pending), Z_FULL_FLUSH (reset history),
Z_FINISH (end stream). */
do {
err = deflate(&self->zst, mode);
/* append output */
} while (err == Z_OK && self->zst.avail_out == 0);
if (mode == Z_FINISH) {
err = deflateEnd(&self->zst);
self->is_initialised = 0;
}
return result;
}

flush(Z_SYNC_FLUSH) forces all pending input to be output without ending the stream. Used in streaming protocols (HTTP chunked transfer, WebSocket).

Decompress.decompress

// CPython: Modules/zlibmodule.c:680 zlib_Decompress_decompress_impl
static PyObject *
zlib_Decompress_decompress_impl(compobject *self, Py_buffer *data,
Py_ssize_t max_length)
{
self->zst.next_in = data->buf;
self->zst.avail_in = data->len;
do {
self->zst.next_out = obuf;
self->zst.avail_out = DEFAULTALLOC;
err = inflate(&self->zst, Z_SYNC_FLUSH);
/* append output; stop if max_length reached */
} while (err == Z_OK && self->zst.avail_out == 0);
if (err == Z_STREAM_END)
self->eof = 1;
return result;
}

max_length limits the output buffer to avoid unbounded memory use on adversarial inputs. Unprocessed input is stored in self->unused_data.

gopy notes

zlib.compressobj/decompressobj are in module/zlib/module.go using Go's compress/zlib, compress/gzip, and compress/flate packages. Compress.compress calls flate.Writer.Write. Compress.flush calls flate.Writer.Flush or Close. Compress.copy uses deflateCopy semantics by re-serializing the stream state.