diff --git a/Doc/library/zlib.rst b/Doc/library/zlib.rst index 339acfd0e5786f..670a3cf2094744 100644 --- a/Doc/library/zlib.rst +++ b/Doc/library/zlib.rst @@ -47,6 +47,11 @@ The available exception and functions in this module are: platforms, use ``adler32(data) & 0xffffffff``. +.. function:: adler32_combine(adler_1, adler_2, len_2) + + Combines two Adler-32 checksums *adler_1* and *adler_2* into one. *len_2* is the length of the string used to generate *adler_2*. + + .. function:: compress(data, /, level=-1) Compresses the bytes in *data*, returning a bytes object containing compressed data. diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index f828b4c737a5fc..f25d7d0374d553 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -48,6 +48,9 @@ def test_adler32empty(self): self.assertEqual(zlib.adler32(b"", 1), 1) self.assertEqual(zlib.adler32(b"", 432), 432) + def test_adler32_combine(self): + self.assertEqual(zlib.adler32_combine(zlib.adler32(b"penguin"), zlib.adler32(b"banana"), len(b"banana")), 636028248) + def test_penguins(self): self.assertEqual(zlib.crc32(b"penguin", 0), 0x0e5c1a120) self.assertEqual(zlib.crc32(b"penguin", 1), 0x43b6aa94) diff --git a/Misc/ACKS b/Misc/ACKS index 78beee5f34eec6..5ad249ccca8f11 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1896,3 +1896,4 @@ Robert Leenders Tim Hopper Dan Lidral-Porter Ngalim Siregar +Callum Attryde diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index 77ea04a353bf14..62fffd2d66fd39 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -704,6 +704,72 @@ zlib_adler32(PyObject *module, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(zlib_adler32_combine__doc__, +"adler32_combine($module, adler_1, adler_2, len_2, /)\n" +"--\n" +"\n" +"Combine two Adler-32 Checksums into one.\n" +"\n" +" adler_1\n" +" First checksum.\n" +" adler_2\n" +" Second checksum.\n" +" len_2\n" +" Length of the buffer used to generate the second checksum.\n" +"\n" +"The returned checksum is an integer."); + +#define ZLIB_ADLER32_COMBINE_METHODDEF \ + {"adler32_combine", (PyCFunction)(void(*)(void))zlib_adler32_combine, METH_FASTCALL, zlib_adler32_combine__doc__}, + +static PyObject * +zlib_adler32_combine_impl(PyObject *module, unsigned int adler_1, + unsigned int adler_2, unsigned int len_2); + +static PyObject * +zlib_adler32_combine(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + unsigned int adler_1; + unsigned int adler_2; + unsigned int len_2; + + if (!_PyArg_CheckPositional("adler32_combine", nargs, 3, 3)) { + goto exit; + } + if (PyFloat_Check(args[0])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + adler_1 = (unsigned int)PyLong_AsUnsignedLongMask(args[0]); + if (adler_1 == (unsigned int)-1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[1])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + adler_2 = (unsigned int)PyLong_AsUnsignedLongMask(args[1]); + if (adler_2 == (unsigned int)-1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + len_2 = (unsigned int)PyLong_AsUnsignedLongMask(args[2]); + if (len_2 == (unsigned int)-1 && PyErr_Occurred()) { + goto exit; + } + return_value = zlib_adler32_combine_impl(module, adler_1, adler_2, len_2); + +exit: + return return_value; +} + PyDoc_STRVAR(zlib_crc32__doc__, "crc32($module, data, value=0, /)\n" "--\n" @@ -785,4 +851,4 @@ zlib_crc32(PyObject *module, PyObject *const *args, Py_ssize_t nargs) #ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF #endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ -/*[clinic end generated code: output=faae38ef96b88b16 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0922ad853778187c input=a9049054013a1b77]*/ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index 3e77080a31cb57..b646663347f3fa 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -1264,6 +1264,31 @@ zlib_adler32_impl(PyObject *module, Py_buffer *data, unsigned int value) return PyLong_FromUnsignedLong(value & 0xffffffffU); } +/*[clinic input] +zlib.adler32_combine + + adler_1: unsigned_int(bitwise=True) + First checksum. + adler_2: unsigned_int(bitwise=True) + Second checksum. + len_2: unsigned_int(bitwise=True) + Length of the buffer used to generate the second checksum. + / + +Combine two Adler-32 Checksums into one. + +The returned checksum is an integer. +[clinic start generated code]*/ + +static PyObject * +zlib_adler32_combine_impl(PyObject *module, unsigned int adler_1, + unsigned int adler_2, unsigned int len_2) +/*[clinic end generated code: output=af156f2b847877ae input=c436395ab679bbc2]*/ +{ + unsigned long value = adler32_combine64(adler_1, adler_2, len_2); + return PyLong_FromUnsignedLong(value & 0xffffffffU); +} + /*[clinic input] zlib.crc32 @@ -1309,6 +1334,7 @@ zlib_crc32_impl(PyObject *module, Py_buffer *data, unsigned int value) static PyMethodDef zlib_methods[] = { ZLIB_ADLER32_METHODDEF + ZLIB_ADLER32_COMBINE_METHODDEF ZLIB_COMPRESS_METHODDEF ZLIB_COMPRESSOBJ_METHODDEF ZLIB_CRC32_METHODDEF @@ -1351,6 +1377,7 @@ PyDoc_STRVAR(zlib_module_documentation, "zlib library, which is based on GNU zip.\n" "\n" "adler32(string[, start]) -- Compute an Adler-32 checksum.\n" +"adler32_combine(adler1, adler2, len2) -- Combine two Adler-32 checksums.\n" "compress(data[, level]) -- Compress data, with compression level 0-9 or -1.\n" "compressobj([level[, ...]]) -- Return a compressor object.\n" "crc32(string[, start]) -- Compute a CRC-32 checksum.\n"