diff --git a/Doc/library/lzma.rst b/Doc/library/lzma.rst index 69f7cb8d48d7ae..deec54fad9ed32 100644 --- a/Doc/library/lzma.rst +++ b/Doc/library/lzma.rst @@ -336,6 +336,39 @@ Miscellaneous feature set. +Information about the version of the lzma library in use is available through +the following constants: + + +.. data:: LZMA_VERSION +.. data:: LZMA_VERSION_STRING + + The version of the lzma C library actually loaded at runtime, in both + integer and string forms. + + .. versionadded:: 3.15 + +.. data:: LZMA_HEADER_VERSION +.. data:: LZMA_HEADER_VERSION_STRING + + The version of the lzma library that was used for building the module, in + both integer and string forms. This may be different from the lzma library + actually used at runtime. + + .. versionadded:: 3.15 + +The version number and string formats are as defined in by C library. The +integer is represented in decimal digits as ``jmmmppps`` where ``j`` is the +major version, ``mmm`` is the minor version, ``ppp`` is the patch level, and +``s`` is the "stability indicator" (2 means stable):: + + >>> import lzma + >>> lzma.LZMA_VERSION + 50020052 + >>> lzma.LZMA_VERSION_STRING + '5.2.5' + + .. _filter-chain-specs: Specifying custom filter chains @@ -357,12 +390,26 @@ options. Valid filter IDs are as follows: * Branch-Call-Jump (BCJ) filters: - * :const:`FILTER_X86` - * :const:`FILTER_IA64` - * :const:`FILTER_ARM` - * :const:`FILTER_ARMTHUMB` - * :const:`FILTER_POWERPC` - * :const:`FILTER_SPARC` + * :const:`!FILTER_X86` + * :const:`!FILTER_IA64` + * :const:`!FILTER_ARM` + * :const:`!FILTER_ARMTHUMB` + * :const:`!FILTER_POWERPC` + * :const:`!FILTER_SPARC` + + The above work on all lzma runtime library versions. + + * :const:`!FILTER_ARM64` + + Only works if the lzma version is 5.4.0 or later. + + .. versionadded:: 3.15 + + * :const:`!FILTER_RISCV` + + Only works if the lzma version is 5.6.0 or later. + + .. versionadded:: 3.15 A filter chain can consist of up to 4 filters, and cannot be empty. The last filter in the chain must be a compression filter, and any other filters must be diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 010abb7d9b9278..7533f62e54ab1d 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -206,6 +206,21 @@ difflib (Contributed by Jiahao Li in :gh:`134580`.) +lzma +---- + +* Add :const:`lzma.LZMA_VERSION`, :const:`lzma.LZMA_HEADER_VERSION`, and + related constants. They report the version of the underlying ``lzma`` library + found at runtime and the header versions used at build time. + (Contributed by Chien Wong in :gh:`115988`.) + +* Add support of new BCJ filters ARM64 and RISC-V via + :const:`!lzma.FILTER_ARM64` and :const:`!lzma.FILTER_RISCV`. Note that the + new filters will work only if runtime library supports them. ARM64 filter + requires ``lzma`` 5.4.0 or newer while RISC-V requires 5.6.0 or newer. + (Contributed by Chien Wong in :gh:`115988`.) + + math ---- diff --git a/Lib/lzma.py b/Lib/lzma.py index 316066d024ea02..5f44a43224baa3 100644 --- a/Lib/lzma.py +++ b/Lib/lzma.py @@ -13,7 +13,10 @@ "CHECK_ID_MAX", "CHECK_UNKNOWN", "FILTER_LZMA1", "FILTER_LZMA2", "FILTER_DELTA", "FILTER_X86", "FILTER_IA64", "FILTER_ARM", "FILTER_ARMTHUMB", "FILTER_POWERPC", "FILTER_SPARC", + "FILTER_ARM64", "FILTER_RISCV", "FORMAT_AUTO", "FORMAT_XZ", "FORMAT_ALONE", "FORMAT_RAW", + "LZMA_HEADER_VERSION", "LZMA_HEADER_VERSION_STRING", + "LZMA_VERSION", "LZMA_VERSION_STRING", "MF_HC3", "MF_HC4", "MF_BT2", "MF_BT3", "MF_BT4", "MODE_FAST", "MODE_NORMAL", "PRESET_DEFAULT", "PRESET_EXTREME", diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py index e93c3c37354e27..fca852dcd4faa9 100644 --- a/Lib/test/test_lzma.py +++ b/Lib/test/test_lzma.py @@ -383,6 +383,20 @@ def test_uninitialized_LZMADecompressor_crash(self): self.assertEqual(LZMADecompressor.__new__(LZMADecompressor). decompress(bytes()), b'') + def test_riscv_filter_constant_exists(self): + self.assertTrue(lzma.FILTER_RISCV) + + def test_arm64_filter_constant_exists(self): + self.assertTrue(lzma.FILTER_ARM64) + + def test_lzma_header_versions(self): + self.assertIsInstance(lzma.LZMA_HEADER_VERSION_STRING, str) + self.assertGreater(lzma.LZMA_HEADER_VERSION, 0) + + def test_lzma_versions(self): + self.assertIsInstance(lzma.LZMA_VERSION_STRING, str) + self.assertGreater(lzma.LZMA_VERSION, 0) + class CompressDecompressFunctionTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2024-03-17-22-16-53.gh-issue-115988.EshSDM.rst b/Misc/NEWS.d/next/Library/2024-03-17-22-16-53.gh-issue-115988.EshSDM.rst new file mode 100644 index 00000000000000..e0d18a88d49d8b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-03-17-22-16-53.gh-issue-115988.EshSDM.rst @@ -0,0 +1,2 @@ +:mod:`lzma` gains C library version info constants and adds constants to +support the newer BCJ filters for ARM64 and RISC-V. diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c index 462c2181fa6036..a5ffb3996c3477 100644 --- a/Modules/_lzmamodule.c +++ b/Modules/_lzmamodule.c @@ -25,6 +25,19 @@ #error "The maximum block size accepted by liblzma is SIZE_MAX." #endif + +/* + * If the lzma.h we're building against is so old as not to define these, this + * provides their equivalent values so that the names remain defined in Python + * regardless of the header versions used at build time. + */ +#ifndef LZMA_FILTER_ARM64 +#define LZMA_FILTER_ARM64 LZMA_VLI_C(0x0A) +#endif +#ifndef LZMA_FILTER_RISCV +#define LZMA_FILTER_RISCV LZMA_VLI_C(0x0B) +#endif + /* On success, return value >= 0 On failure, return -1 */ static inline Py_ssize_t @@ -379,6 +392,8 @@ lzma_filter_converter(_lzma_state *state, PyObject *spec, void *ptr) case LZMA_FILTER_ARM: case LZMA_FILTER_ARMTHUMB: case LZMA_FILTER_SPARC: + case LZMA_FILTER_ARM64: + case LZMA_FILTER_RISCV: f->options = parse_filter_spec_bcj(state, spec); return f->options != NULL; default: @@ -497,7 +512,9 @@ build_filter_spec(const lzma_filter *f) case LZMA_FILTER_IA64: case LZMA_FILTER_ARM: case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: { + case LZMA_FILTER_SPARC: + case LZMA_FILTER_ARM64: + case LZMA_FILTER_RISCV: { lzma_options_bcj *options = f->options; if (options) { ADD_FIELD(options, start_offset); @@ -1559,6 +1576,8 @@ lzma_exec(PyObject *module) ADD_INT_PREFIX_MACRO(module, FILTER_ARMTHUMB); ADD_INT_PREFIX_MACRO(module, FILTER_SPARC); ADD_INT_PREFIX_MACRO(module, FILTER_POWERPC); + ADD_INT_PREFIX_MACRO(module, FILTER_ARM64); + ADD_INT_PREFIX_MACRO(module, FILTER_RISCV); ADD_INT_PREFIX_MACRO(module, MF_HC3); ADD_INT_PREFIX_MACRO(module, MF_HC4); ADD_INT_PREFIX_MACRO(module, MF_BT2); @@ -1599,6 +1618,27 @@ lzma_exec(PyObject *module) return -1; } + if (PyModule_AddStringConstant( + module, "LZMA_HEADER_VERSION_STRING", + LZMA_VERSION_STRING) < 0) { + return -1; + } + if (PyModule_AddStringConstant( + module, "LZMA_VERSION_STRING", + lzma_version_string()) < 0) { + return -1; + } + PyObject *uint32_obj = PyLong_FromUnsignedLong(LZMA_VERSION); + if (PyModule_AddObject(module, "LZMA_HEADER_VERSION", uint32_obj) < 0) { + Py_XDECREF(uint32_obj); + return -1; + } + uint32_obj = PyLong_FromUnsignedLong(lzma_version_number()); + if (PyModule_AddObject(module, "LZMA_VERSION", uint32_obj) < 0) { + Py_XDECREF(uint32_obj); + return -1; + } + return 0; }
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: