diff --git a/.gitignore b/.gitignore index 74cecaf..8d62283 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ __pycache__/ tests/docs/api tests/docs/build .tox/ +*/*/_native.src/target +*/*/_native.*.so +*/*/_native.*.dll diff --git a/dissect/util/_native.src/Cargo.lock b/dissect/util/_native.src/Cargo.lock new file mode 100644 index 0000000..c77a35a --- /dev/null +++ b/dissect/util/_native.src/Cargo.lock @@ -0,0 +1,234 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "_native" +version = "0.0.0-git" +dependencies = [ + "lz4_flex", + "lzokay-native", + "pyo3", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "lzokay-native" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "792ba667add2798c6c3e988e630f4eb921b5cbc735044825b7111ef1582c8730" +dependencies = [ + "byteorder", + "thiserror", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pyo3" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51" +dependencies = [ + "cfg-if", + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179" +dependencies = [ + "once_cell", + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unindent" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" diff --git a/dissect/util/_native.src/Cargo.toml b/dissect/util/_native.src/Cargo.toml new file mode 100644 index 0000000..2aa893d --- /dev/null +++ b/dissect/util/_native.src/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "_native" +version = "0.0.0-git" +edition = "2021" + +[lib] +name = "_native" +crate-type = ["cdylib"] + +[dependencies] +pyo3 = "0.22" +lz4_flex = "0.11" +lzokay-native = "0.1" diff --git a/dissect/util/_native.src/src/compression.rs b/dissect/util/_native.src/src/compression.rs new file mode 100644 index 0000000..bd2fef7 --- /dev/null +++ b/dissect/util/_native.src/src/compression.rs @@ -0,0 +1,11 @@ +use pyo3::prelude::*; + +mod lz4; +mod lzo; + +pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> { + let submodule = PyModule::new_bound(m.py(), "compression")?; + lz4::create_submodule(&submodule)?; + lzo::create_submodule(&submodule)?; + m.add_submodule(&submodule) +} diff --git a/dissect/util/_native.src/src/compression/lz4.rs b/dissect/util/_native.src/src/compression/lz4.rs new file mode 100644 index 0000000..54c65bf --- /dev/null +++ b/dissect/util/_native.src/src/compression/lz4.rs @@ -0,0 +1,58 @@ +use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; +use pyo3::types::{PyByteArray, PyBytes}; + +const MAX_DISCOVER_OUTPUT_SIZE: usize = 1024 * 1024 * 1024; + +#[pyfunction] +#[pyo3(signature = (src, uncompressed_size=-1, return_bytearray=false))] +fn decompress( + py: Python<'_>, + src: Vec, + uncompressed_size: isize, + return_bytearray: bool, +) -> PyResult { + let result = if uncompressed_size < 0 { + // If the uncompressed size is not provided, we need to discover it first + let mut output_size = lz4_flex::block::get_maximum_output_size(src.len()); + loop { + // If the output size is too large, we should not attempt to decompress further + if output_size > MAX_DISCOVER_OUTPUT_SIZE { + return Err(PyErr::new::( + "output size is too large".to_string(), + )); + } + + match lz4_flex::block::decompress(&src, output_size) { + Ok(result) => { + break result; + } + Err(lz4_flex::block::DecompressError::OutputTooSmall { + expected, + actual: _, + }) => { + output_size = expected; + } + Err(e) => { + return Err(PyErr::new::(e.to_string())); + } + } + } + } else { + lz4_flex::block::decompress(&src, uncompressed_size as usize) + .map_err(|e| PyErr::new::(e.to_string()))? + }; + + let pyresult = PyBytes::new_bound(py, &result); + if return_bytearray { + Ok(PyByteArray::from_bound(&pyresult)?.into()) + } else { + Ok(pyresult.into()) + } +} + +pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> { + let submodule = PyModule::new_bound(m.py(), "lz4")?; + submodule.add_function(wrap_pyfunction!(decompress, m)?)?; + m.add_submodule(&submodule) +} diff --git a/dissect/util/_native.src/src/compression/lzo.rs b/dissect/util/_native.src/src/compression/lzo.rs new file mode 100644 index 0000000..b8c7ac0 --- /dev/null +++ b/dissect/util/_native.src/src/compression/lzo.rs @@ -0,0 +1,39 @@ +use pyo3::exceptions::PyValueError; +use pyo3::prelude::*; +use pyo3::types::PyBytes; + +#[pyfunction] +#[pyo3(signature = (src, header=true, buflen=-1))] +fn decompress( + py: Python<'_>, + src: Vec, + header: bool, + buflen: isize, +) -> PyResult> { + let (src, out_len) = if header { + if src.len() < 8 || src[0] < 0xf0 || src[0] > 0xf1 { + return Err(PyErr::new::( + "Invalid header value".to_string(), + )); + } + let len = u32::from_le_bytes([src[1], src[2], src[3], src[4]]) as usize; + (src[5..].to_vec(), len) + } else if buflen < 0 { + return Err(PyErr::new::( + "Buffer length must be provided".to_string(), + )); + } else { + (src, buflen as usize) + }; + + let mut cursor = std::io::Cursor::new(src); + lzokay_native::decompress(&mut cursor, Some(out_len)) + .map_err(|e| PyErr::new::(e.to_string())) + .map(|result| PyBytes::new_bound(py, &result)) +} + +pub fn create_submodule(m: &Bound<'_, PyModule>) -> PyResult<()> { + let submodule = PyModule::new_bound(m.py(), "lzo")?; + submodule.add_function(wrap_pyfunction!(decompress, m)?)?; + m.add_submodule(&submodule) +} diff --git a/dissect/util/_native.src/src/lib.rs b/dissect/util/_native.src/src/lib.rs new file mode 100644 index 0000000..39d24f9 --- /dev/null +++ b/dissect/util/_native.src/src/lib.rs @@ -0,0 +1,10 @@ +use pyo3::prelude::*; + +mod compression; + + +#[pymodule] +fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> { + compression::create_submodule(m)?; + Ok(()) +} diff --git a/dissect/util/compression/__init__.py b/dissect/util/compression/__init__.py index 0e28818..57b2e3b 100644 --- a/dissect/util/compression/__init__.py +++ b/dissect/util/compression/__init__.py @@ -1,47 +1,32 @@ from dissect.util.compression import lz4 as lz4_python from dissect.util.compression import lzo as lzo_python -# This selects between the native version of lz4 (when installed) and our own +# This selects between the native version of lz4 and lzo (when installed) and our own # pure-Python implementation. # # By doing a: # from dissect.util.compression import lz4 -# -# in another project will automatically give you one or the other. -# -# The native version is also available as dissect.util.compression.lz4_native -# (when installed) and the pure Python version is always available as -# dissect.util.compression.lz4_python. -# -# Note that the pure Python implementation is not a full replacement of the -# native lz4 Python package: only the decompress() function is implemented. -try: - import lz4.block as lz4 - import lz4.block as lz4_native -except ImportError: - lz4 = lz4_python - lz4_native = None - -# This selects between the native version of lzo (when installed) and our own -# pure-Python implementation. -# -# By doing a: +# or # from dissect.util.compression import lzo # # in another project will automatically give you one or the other. # -# The native version is also available as dissect.util.compression.lzo_native -# (when installed) and the pure Python version is always available as +# The native version is also available as dissect.util.compression.lz4_native +# and dissect.util.compression.lzo_native (when installed) and the pure Python +# version is always available as dissect.util.compression.lz4_python and # dissect.util.compression.lzo_python. # # Note that the pure Python implementation is not a full replacement of the -# native lzo Python package: only the decompress() function is implemented. +# native lz4 and lzo Python package: only the decompress() function is implemented. try: - import lzo - import lzo as lzo_native + from dissect.util import _native + + lz4 = lz4_native = _native.compression.lz4 + lzo = lzo_native = _native.compression.lzo except ImportError: + lz4 = lz4_python lzo = lzo_python - lzo_native = None + lz4_native = lzo_native = None __all__ = [ "lz4", diff --git a/dissect/util/compression/lz4.py b/dissect/util/compression/lz4.py index 5ddd622..12c73d1 100644 --- a/dissect/util/compression/lz4.py +++ b/dissect/util/compression/lz4.py @@ -27,19 +27,14 @@ def _get_length(src: BinaryIO, length: int) -> int: def decompress( src: bytes | BinaryIO, uncompressed_size: int = -1, - max_length: int = -1, return_bytearray: bool = False, - return_bytes_read: bool = False, ) -> bytes | tuple[bytes, int]: """LZ4 decompress from a file-like object up to a certain length. Assumes no header. Args: src: File-like object to decompress from. - uncompressed_size: Ignored, present for compatibility with native lz4. The ``max_length`` - parameter sort-of but not completely has the same function. - max_length: Decompress up to this many result bytes. + uncompressed_size: Ignored, present for compatibility with native lz4. return_bytearray: Whether to return ``bytearray`` or ``bytes``. - return_bytes_read: Whether to return a tuple of ``(data, bytes_read)`` or just the data. Returns: The decompressed data or a tuple of the decompressed data and the amount of bytes read. @@ -48,28 +43,26 @@ def decompress( src = io.BytesIO(src) dst = bytearray() - start = src.tell() min_match_len = 4 while True: - read_buf = src.read(1) - if len(read_buf) == 0: + if len(read_buf := src.read(1)) == 0: raise CorruptDataError("EOF at reading literal-len") token = ord(read_buf) literal_len = _get_length(src, (token >> 4) & 0xF) - read_buf = src.read(literal_len) + if len(dst) + literal_len > uncompressed_size > 0: + raise CorruptDataError("Decompressed size exceeds uncompressed_size") - if len(read_buf) != literal_len: + if len(read_buf := src.read(literal_len)) != literal_len: raise CorruptDataError("Not literal data") - dst.extend(read_buf) - if len(dst) == max_length: + dst.extend(read_buf) + if len(dst) >= uncompressed_size > 0: break - read_buf = src.read(2) - if len(read_buf) == 0: + if len(read_buf := src.read(2)) == 0: token_and = token & 0xF if token_and != 0: raise CorruptDataError(f"EOF, but match-len > 0: {token_and}") @@ -78,21 +71,22 @@ def decompress( if len(read_buf) != 2: raise CorruptDataError("Premature EOF") - (offset,) = struct.unpack("> 0) & 0xF) match_len += min_match_len + if len(dst) + match_len > uncompressed_size > 0: + raise CorruptDataError("Decompressed size exceeds uncompressed_size") + for _ in range(match_len): dst.append(dst[-offset]) + if len(dst) >= uncompressed_size > 0: + break + if not return_bytearray: dst = bytes(dst) - if return_bytes_read: - return dst, src.tell() - start - - return dst + return dst[:uncompressed_size] if uncompressed_size > 0 else dst diff --git a/pyproject.toml b/pyproject.toml index 55ac04a..a23e289 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,16 +31,6 @@ homepage = "https://dissect.tools" documentation = "https://docs.dissect.tools/en/latest/projects/dissect.util" repository = "https://github.com/fox-it/dissect.util" -[project.optional-dependencies] -lzo = [ - # There are no Windows PyPy wheels available for python-lzo - # So we use a pure python fallback for it. - "python-lzo; platform_system != 'Windows' or platform_python_implementation != 'PyPy'", -] -lz4 = [ - "lz4", -] - [project.scripts] dump-nskeyedarchiver = "dissect.util.tools.dump_nskeyedarchiver:main" @@ -102,3 +92,8 @@ license-files = ["LICENSE", "COPYRIGHT"] include = ["dissect.*"] [tool.setuptools_scm] + +[tool.maturin] +module-name = "dissect.util._native" +manifest-path = "dissect/util/_native.src/Cargo.toml" +features = ["pyo3/extension-module"] diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..e89681a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,19 @@ +from types import ModuleType + +import pytest + + +@pytest.fixture(scope="session", params=[True, False], ids=["native", "python"]) +def lz4(request: pytest.FixtureRequest) -> ModuleType: + if request.param: + return pytest.importorskip("dissect.util._native", reason="No _native module available").compression.lz4 + + return pytest.importorskip("dissect.util.compression.lz4") + + +@pytest.fixture(scope="session", params=[True, False], ids=["native", "python"]) +def lzo(request: pytest.FixtureRequest) -> ModuleType: + if request.param: + return pytest.importorskip("dissect.util._native", reason="No _native module available").compression.lzo + + return pytest.importorskip("dissect.util.compression.lzo") diff --git a/tests/test_compression.py b/tests/test_compression.py index 72b772b..68d35f8 100644 --- a/tests/test_compression.py +++ b/tests/test_compression.py @@ -1,13 +1,14 @@ import hashlib import lzma from io import BytesIO +from types import ModuleType import pytest -from dissect.util.compression import lz4, lznt1, lzo, lzxpress, lzxpress_huffman, sevenbit, xz +from dissect.util.compression import lznt1, lzxpress, lzxpress_huffman, sevenbit, xz -def test_lz4_decompress() -> None: +def test_lz4_decompress(lz4: ModuleType) -> None: assert ( lz4.decompress(b"\xff\x0cLZ4 compression test string\x1b\x00\xdbPtring") == b"LZ4 compression test string" * 10 ) @@ -26,190 +27,193 @@ def test_lznt1_decompress() -> None: ) -def test_lzo_decompress() -> None: - assert ( - lzo.decompress(bytes.fromhex("0361626361626320f314000f616263616263616263616263616263616263110000"), False) - == b"abc" * 100 - ) - - assert ( - hashlib.sha256( - lzo.decompress( - bytes.fromhex( - "160900a40100400003a83e8e6302003800007104ff4000fc012add00032016dd" - "00042016dd00052016dd00062016dd00072016dd00082016dd00092016dd000a" - "2016dd000b2016dd000c2016dd000d2016dd000e2016dd000f2016dd00102016" - "dd00112016dd00122016dd00132016dd00142016dd00152016dd00162016dd00" - "172016dd00182016dd00192016dd001a2016dd001b2016dd001c2016dd001d20" - "16dd001e2016dd001f2016dd00202016dd00212016dd00222016dd00232016dd" - "00242016dd00252016dd00262016dd00272016dd00282016dd00292016dd002a" - "2016dd002b2016dd002c2016dd002d2016dd002e2016dd002f2016dd00302016" - "dd00312016dd00322016dd00332016dd00342016dd00352016dd00362016dd00" - "372016dd00382016dd00392016dd003a2016dd003b2016dd003c2016dd003d20" - "16dd003e2016dd003f2016dd00402016dd00412016dd00422016dd00432016dd" - "00442016dd00452016dd00462016dd00472016dd00482016dd00492016dd004a" - "2016dd004b2016dd004c2016dd004d2016dd004e2016dd004f2016dd00502016" - "dd00512016dd00522016dd00532016dd00542016dd00552016dd00562016dd00" - "572016dd00582016dd00592016dd005a2016dd005b2016dd005c2016dd005d20" - "16dd005e2016dd005f2016dd00602016dd00612016dd00622016dd00632016dd" - "00642016dd0065200adf000800ed27dc006001228d57e32501556c29dc00fd0b" - "f55d04662b5c00307d010031dd004f5d06675c0027ce06c03f3b5e02e4022059" - "0e00880228dd02115d16682002bc03ff020a00ff8902c75d0669dc0322dc5507" - "736d616c6c2d66696c652a9500d455046ad404229455016469722f6f045f3639" - "2a9a00eb4209096bd80422b0526804082d776974682d78617474722a1e077543" - "080a7c3622cd5d91cd126d9500e0943a110000" - ), - False, - 8192, - ) - ).hexdigest() - == "a4d6951085717a9698cd814899d11c931db1d4c0f7ddc3b1cba0f582142d4cf4" - ) - - assert ( - hashlib.sha256( - lzo.decompress( - bytes.fromhex( - "290000352abd61b0010000d6100000020000000c03d304a5016d01a457000000" - "155d03e6440102c8d82a07ff40006f02e8276a540006020174800100d5fc018e" - "015dffbc006d0032292d00fc292c006d00425d01d04d00376d00a0286e00a6fd" - "2c9c00ee0087b90901724e0548d90e00def60d00a84d019d4212f8d428be00c1" - "f5282e002cdd0a0115f3342c013e0c0001e82700012add03e7470108239327dc" - "030bd45a04008b6e000089620000ec1d6d24ed27ad00e96e05129427ac000b58" - "2a050082db000013f00000fb402cad00ea4701981e9627ac00002438b73200f7" - "d80000b3ef00005008010006e2000033e100001d0a0100dfcb00004cbe000017" - "f4000055e5000025e30000ebd50000e1dd5d01bc0d009a4e01b5d20e00d1e84c" - "384d0dbe5e0247cf0e0086140e0e09830e01f5810d009b4e00af7f0e00bd3b0d" - "0001dc107d3ee829dc07013400dc072edd07eb47014bf9aa279c0207083f0900" - "6f8000002d7c5d0a5f5d0cea0e00939c2c4d01a5cd0a045c01036d010d08a301" - "28ec030243547e5aee4701b6dcad274d01855e294522280d012c4d08ed295c02" - "031e007709ec01287c006d08ef297f000300922b7c007d07ec290d022c5c032a" - "0c020257a8bc61f24601fbfe280e0260f2014a1e4e2dec070d00bc5e005b0b0e" - "00530f0e00b1e60d06bf5e00d20e0e0088b40e02a2855d07970e00967d0e005e" - "a50e00145a0e00b0300e00f97b0e00aa490d00ac0f8f001c2b0e0016130e008e" - "210d003c0b750007890e0010710e007a8f5d34a00e00f79e5d1dac0d00b44d01" - "014d00905e081aa20e00c19b0e00baa60e00dbad0e008fa30e0091a10d00754e" - "2bc9940d00de4d061b5d039c5e05c0950d00ff4e0a148d0d00a54e3a5ca40d00" - "0f5d12224e3d509a5d232a4c1b5e0f6e1a0d00484e547a165d47144c364e01f5" - "1c4c225d023b4e00161b5c335e0019820e007d785c154e0040ba289d044c5c24" - "7b68b65ecf279c040698932b022cbf0000d34d21615d4b805e240dde4d1e0c0e" - "01dd010d00e35d00175e028e180d001d4e29c21a0e006d110d00af5e00dd120d" - "00ab4e02a6060d00e64e01edf90e0d6a170e01be090d00c05e2bf8050d00695e" - "026d100e0065130e00acfd5c554d2fe15e31ea190d00104d0b8b4d075c5d0405" - "5975855e076bfb0e00b2f25d24aa4d1dec0e00abee5d28e70e00cec65c464e32" - "8d774c255e23a8a94c1e5d36445e270c8c5c2c5e24f2925d1e6f0d00bc5e1e6c" - "8b0d00cc5e3384460e00677e0e0028694c304d66014e2c0a3f0e005b445d3670" - "0d00a05d33235e001d910d003d5e2d92640d006f4e34fcab0d00e45d38135e36" - "d1a80d00d25e00b99d0e004d900d00c55e3755875c044d34185d060f5d3a5d4d" - "39bc4d04cc4e39d6935c465e3fae6b0d00dd5e4429650d00734d12ce4d0fe74d" - "01034e4a33234c0f5e3ae54e5d0ed10e3e07fe0e00666e0d002f5d06864d1796" - "5d0f4e4e0170d70d00ca5e8164cc5c085d48644d113d5d13184d11e55e13ce28" - "0d00ee4d43b25d3eca5d41435d423e4e00a01e4e271a00203801003a42716c19" - "5c574d0c7e4d007f4e4fa21b20111e01db0d0e0042680d00465d38375d1d8d4d" - "28f54d60004e929c995c614d26205d36d45d2e7a4d64da4d01f55d3aa85e0076" - "9f4c1e4e258e980d000b4e06e3880d00fa5e02c6614c235d409d4d7a915e06f3" - "3d0d00264e7781240d00414e7b888b0d59035e2d69730e0098605d39960d003f" - "4d0f434d2b264d00894e49b0ae4c2f4d12b64d4c594d01814d43cd4d01eb4d02" - "af4d05025d33054d3bff5e40b5735d07355c7e4e2e4c2e5d09425e323a009dd5" - "085e0c56150e007d675d07a75d14af0e001fb24c044d58384d001a5e0d0cb50d" - "00365d08974d06b15db9a45d15ad4d01a34e0149410e00798a0e002fb94c5b5e" - "10c3c44cb44e08adb04c514d8e804d17924e12e3c05c854d7d474d42394d4de2" - "4d24fa4e0896375d984d5c644eb257394dcb5fae1f99c60d00a44d9d834e1832" - "b70e0082550d03414d11064d57c95d12724e1de6da5d1a765c674d6e224e0351" - "755d0f795c305e6db1544c0b5d500a5e0cbd8e0e0021560d002b4d9a1e4d2ed2" - "5e395b7728fd162a5db7f1297c17034000bb09f0017dbcff9c0302e645a560f4" - "9cbd4c694c000c6c69625831312e736f2e362e332e30f8d77804225420013b0e" - "6b08279917830dba8d5a8a341b01061b498bb45a89442c0e00e98c5c014e0c90" - "de49944b58935a89362f28c80102b2a19e5ef62dca016175a90e3028c8017904" - "f747016aea7727c90180463d721528280102c72bb858f8c90911c80901646d63" - "702f30016105f94601dcff283201945559212728300102664d4b54fad10910d3" - "09657874ad0934282d01685d04fb47011c2778272e0110390204aa7e282c0102" - "d782aa4ffc2d8e0373736909312a5902d8580422a226c6a5282a01d82545e011" - "28280102b5c4a461fec909124d006e0d112f58090866726565626c332e63686b" - "2aa500ff2934042da600736f2aa00074417101162ea00001707269762f590101" - "d5051534b4002868010387d1a85a02022b1005016764626d651f352ae4037d04" - "035e04bfb728e60378e55db87a28e4030312a7bc6104022b1105690213676d96" - "0931312a990005d90413309a002e3228d4016905064b057b327927d4010314b7" - "0700f6c35571b6448465f0b028040275f6072c34030469676678636d72994237" - "2a9d0008dd0414319c002a0c026d05094f050c687c270d0270520cc7c55d0f04" - "28c4280251d18e5a0a5f04de317d279e00b0fd061c301d0a0776de289c007933" - "0b5f04842d7f279c0003f8d11700c5fa04904512aa21562053fe21b42146a063" - "bd500321f62b45ce449e5599ab55da05468b076f2c3d010c5f09098688273e01" - "4c970204ef040a07163b286c040247d30a5a0d2ccc0305706970656c696e65bd" - "5c3528cc036d050e4f050ec689274d0100563d0774283d01805d220f303e0177" - "690f992d302e6e4c2e302aad0010cd051a35af002e3333952eed27c500114706" - "153a8a28be093a0c0535e75db2f8217d3105409721ed245f5ea8f05e4daf122c" - "2506124f076d398f27ee00e4454dc2232c8d00134e04ea5c288d00c456951317" - "2c6505144e04fd73288e00a80a0d341142a72562282404023a54de5e152c420b" - "737102017465c31b382e36e80a6905164b0533dc90274a01acd402ff86330a07" - "f53e59ca480e0008490e00bd435140410e00182521582e214a23f7b82c590217" - "4f0802199b283c13018b05003e49e7db5ebbd29628690216416818c9130ea813" - "0276612d64728d6d322a9500192c2807299400012e3930302860066d051a4f05" - "edc29d27f501c04aa080122cd5011b2fd701676c782fd5011c2fd401f40430d5" - "011d693ad528d5016c5ae8a7282cd6011e0228e015bc09047761796c616e642f" - "e5011fc5051833a40030f501205e0514fe28f501a421b22c5d1d2cf501212fcd" - "0378acf32be501222fcc03f40430d501234f05711b9e27d601e06651cd2e2cd5" - "0124dd090afc092fc501252c4814c40430b501265e046a4a28b6017006061131" - "e021f1244428c401028b832b5b272c9317786362a588312804117904285b04e8" - "6e9f285512a60204afb321dd32322c310b2a725955a0279e0083038d00012a8d" - "002b4e048558288d00a44a4eb90e2c1d012c4e043e673c1d012d4e04c16a288c" - "00035c560b0095ec581e55a5e4210d42b8219e35fd90218d35652c6d012e5f06" - "5e37a627dc00030471060047d941506f090861213e298f142cbd002f5f053c55" - "a93b2d02307de958288e008c27010896210e43286c2c2d01315f047db5aa3b2d" - "01324e0400b9288c000214ba0400214ea432d021ad46342c8e422902287c2902" - "da00f809f0297c407dae3443033fc3ac272d01d44ea7441c2c8d00354e0483df" - "288e0040260a0686632c8d003676d243ad278d002c46f6354e2c8d00376d3691" - "288e000c470d2d5f214e3b90c94d13112cad00384f05075faf28ac005d099c2d" - "3d01394e04a3ad288e0048964db5ac2c8d003a4f04c859b028ec024a797b1e2c" - "8d003b4e044378288d000421ee3b4a462c8d003c4e048dbe288d00544e04b343" - "2c8d003d4f044002b1278d00f44ecc8c162c8d003e4e04cc18288e00d4a541c5" - "3d2c8d003f4e040656288e00c0d60180794e2416952c9d00405f0495b4b2279e" - "0098170da9fa216621d8e24c3121ce3fc30a2cbd004172d12fb527bd00244e2a" - "1c4a2c8d00424e044f79288d00945e1c09472c8d00434f0458c0b52b4a184914" - "2c8d00444e04a1d4288d00145e292f212c8d00454e04d0f5288e0084e60e3922" - "645df79a2c9d00466e58f4b62804255e2a67172c8d00474f043d0cb728a01d4e" - "12cd102c8d00484e040a1d288d00145e1f74402c8d00494f047e5db72b7e0693" - "39284d0d314d6a33294c0d018b03cf0a2e4d0d4c42031197280c0103d88d0900" - "4ef35c1a5d7dae4e0e0dc54d91422c4d014b294c01032d00570e4a022c4d014e" - "5f015a39bb287d24a60a06d38c2c0d014d290f012b00812f0d01505e012dc628" - "0d018c22fd3d802c0d014f2b1d02a92f0d01525f01aa46bc270d017c4e19bd60" - "2c0d0151290f012800d32f0d01545e0167a7280d01dc4e8e0b222c8d00554e04" - "72c9288d00185e1da4bf2c9d0153299f013e00f82f9d01575f011689bd28be07" - "86014c9d2c0d0156290d012505c70f2e0d01595f01554cbe284d28950a0662af" - "2c0d01582bcd04552f0d015b5e01b7fb280d01fc4eb53f7a2c0d015a2b0d017f" - "2f0d015d5f01f675bf28b53dd55d7b662c0d015c290f012700a98c082a7d004a" - "dd030b5d01a907c70ff0012cad18f0252d42065c0101060573102a2c59027cfb" - "655b5f5e07b9dc280e0268364d5a1d28fc1a6d04604e049dfa288e00b09b0104" - "81219e54872b2858217d04612c5821026d616e2d3200cf22142d2a3901625b04" - "a53ac128e8045a8374302c2a0163022b90414a0964622730012aa10064c1050d" - "4f002e2e2f48000162696e2f5c052a9103655204196b28c50138521cd81a2cc5" - "016629f0022b220164622a2901675a04f1852829010821ae561a622cfd5e5e29" - "cc0602a9007615a3295c62028ee74f586a42030be8280c015b88006d00288c00" - "02d39fc85a6b4d0478298e0053075915042c9d0169299c01032f001c1668022c" - "7d0068dd03035c01021f004816a32d6d08a3cd43085c01027b0064167a2d6d08" - "6d5e077bec280d02f05eafa70f2c8d016c290f021f00dccc0828114b70420322" - "fc280e015da45dab2e2c8d00734f04ad2ac2278c004f410009002c8d00744d04" - "b6298d00546c192dad01756d722b288d00b85d01a92dcd037229bc02034200f8" - "1671022c0d01775e01602d280d018e21fe5cc70e2c8d007870074000ed04002d" - "ad0279353c032a1d02762b1e0237172e1d027b5e01273c280d01634503042dbd" - "037c4e042b3d288d00554503062d8d007d4e04313e288d00cd524106022c2d02" - "7a2b2d02762f2d027e5e013740280d01ea4ed4dc182c8d00804e041359288c00" - "223d2b7d2d2d02813ddd04822002dd047f2bad02b52fad02845e01905a280d01" - "8d21927037432c8d00853d1d028620021d02832b1d02f42f1d02885e01c79d28" - "0e01fcbf05d9dd218d6df821dd2179216d5e34219e5a9e202ccd00894f06e7b3" - "c327cd005a4503052d0d058a4e04ecb4288d009e4e1075042c6d02872b6e0233" - "182e6d028c5e0161b9280e018f8d4d4d192c8d008d3d8d048e20028d048b2b1d" - "02722f1d02905e0188d2281d026a45030b2dbd03914e0493d3288d005c45030c" - "278c00110000" - ), - False, - 8192, - ) - ).hexdigest() - == "efcff6f6fddf392a7d63966d2441accb27a62d61fe9aa57c5cb521d75e871f0c" - ) - - assert lzo.decompress(bytes.fromhex("f0000000041574657374110000")) == b"test" +@pytest.mark.parametrize( + ("data", "header", "buflen", "digest"), + [ + ( + bytes.fromhex("0361626361626320f314000f616263616263616263616263616263616263110000"), + False, + 300, + "d9f5aeb06abebb3be3f38adec9a2e3b94228d52193be923eb4e24c9b56ee0930", + ), + ( + bytes.fromhex( + "160900a40100400003a83e8e6302003800007104ff4000fc012add00032016dd" + "00042016dd00052016dd00062016dd00072016dd00082016dd00092016dd000a" + "2016dd000b2016dd000c2016dd000d2016dd000e2016dd000f2016dd00102016" + "dd00112016dd00122016dd00132016dd00142016dd00152016dd00162016dd00" + "172016dd00182016dd00192016dd001a2016dd001b2016dd001c2016dd001d20" + "16dd001e2016dd001f2016dd00202016dd00212016dd00222016dd00232016dd" + "00242016dd00252016dd00262016dd00272016dd00282016dd00292016dd002a" + "2016dd002b2016dd002c2016dd002d2016dd002e2016dd002f2016dd00302016" + "dd00312016dd00322016dd00332016dd00342016dd00352016dd00362016dd00" + "372016dd00382016dd00392016dd003a2016dd003b2016dd003c2016dd003d20" + "16dd003e2016dd003f2016dd00402016dd00412016dd00422016dd00432016dd" + "00442016dd00452016dd00462016dd00472016dd00482016dd00492016dd004a" + "2016dd004b2016dd004c2016dd004d2016dd004e2016dd004f2016dd00502016" + "dd00512016dd00522016dd00532016dd00542016dd00552016dd00562016dd00" + "572016dd00582016dd00592016dd005a2016dd005b2016dd005c2016dd005d20" + "16dd005e2016dd005f2016dd00602016dd00612016dd00622016dd00632016dd" + "00642016dd0065200adf000800ed27dc006001228d57e32501556c29dc00fd0b" + "f55d04662b5c00307d010031dd004f5d06675c0027ce06c03f3b5e02e4022059" + "0e00880228dd02115d16682002bc03ff020a00ff8902c75d0669dc0322dc5507" + "736d616c6c2d66696c652a9500d455046ad404229455016469722f6f045f3639" + "2a9a00eb4209096bd80422b0526804082d776974682d78617474722a1e077543" + "080a7c3622cd5d91cd126d9500e0943a110000" + ), + False, + 8192, + "a4d6951085717a9698cd814899d11c931db1d4c0f7ddc3b1cba0f582142d4cf4", + ), + ( + bytes.fromhex( + "290000352abd61b0010000d6100000020000000c03d304a5016d01a457000000" + "155d03e6440102c8d82a07ff40006f02e8276a540006020174800100d5fc018e" + "015dffbc006d0032292d00fc292c006d00425d01d04d00376d00a0286e00a6fd" + "2c9c00ee0087b90901724e0548d90e00def60d00a84d019d4212f8d428be00c1" + "f5282e002cdd0a0115f3342c013e0c0001e82700012add03e7470108239327dc" + "030bd45a04008b6e000089620000ec1d6d24ed27ad00e96e05129427ac000b58" + "2a050082db000013f00000fb402cad00ea4701981e9627ac00002438b73200f7" + "d80000b3ef00005008010006e2000033e100001d0a0100dfcb00004cbe000017" + "f4000055e5000025e30000ebd50000e1dd5d01bc0d009a4e01b5d20e00d1e84c" + "384d0dbe5e0247cf0e0086140e0e09830e01f5810d009b4e00af7f0e00bd3b0d" + "0001dc107d3ee829dc07013400dc072edd07eb47014bf9aa279c0207083f0900" + "6f8000002d7c5d0a5f5d0cea0e00939c2c4d01a5cd0a045c01036d010d08a301" + "28ec030243547e5aee4701b6dcad274d01855e294522280d012c4d08ed295c02" + "031e007709ec01287c006d08ef297f000300922b7c007d07ec290d022c5c032a" + "0c020257a8bc61f24601fbfe280e0260f2014a1e4e2dec070d00bc5e005b0b0e" + "00530f0e00b1e60d06bf5e00d20e0e0088b40e02a2855d07970e00967d0e005e" + "a50e00145a0e00b0300e00f97b0e00aa490d00ac0f8f001c2b0e0016130e008e" + "210d003c0b750007890e0010710e007a8f5d34a00e00f79e5d1dac0d00b44d01" + "014d00905e081aa20e00c19b0e00baa60e00dbad0e008fa30e0091a10d00754e" + "2bc9940d00de4d061b5d039c5e05c0950d00ff4e0a148d0d00a54e3a5ca40d00" + "0f5d12224e3d509a5d232a4c1b5e0f6e1a0d00484e547a165d47144c364e01f5" + "1c4c225d023b4e00161b5c335e0019820e007d785c154e0040ba289d044c5c24" + "7b68b65ecf279c040698932b022cbf0000d34d21615d4b805e240dde4d1e0c0e" + "01dd010d00e35d00175e028e180d001d4e29c21a0e006d110d00af5e00dd120d" + "00ab4e02a6060d00e64e01edf90e0d6a170e01be090d00c05e2bf8050d00695e" + "026d100e0065130e00acfd5c554d2fe15e31ea190d00104d0b8b4d075c5d0405" + "5975855e076bfb0e00b2f25d24aa4d1dec0e00abee5d28e70e00cec65c464e32" + "8d774c255e23a8a94c1e5d36445e270c8c5c2c5e24f2925d1e6f0d00bc5e1e6c" + "8b0d00cc5e3384460e00677e0e0028694c304d66014e2c0a3f0e005b445d3670" + "0d00a05d33235e001d910d003d5e2d92640d006f4e34fcab0d00e45d38135e36" + "d1a80d00d25e00b99d0e004d900d00c55e3755875c044d34185d060f5d3a5d4d" + "39bc4d04cc4e39d6935c465e3fae6b0d00dd5e4429650d00734d12ce4d0fe74d" + "01034e4a33234c0f5e3ae54e5d0ed10e3e07fe0e00666e0d002f5d06864d1796" + "5d0f4e4e0170d70d00ca5e8164cc5c085d48644d113d5d13184d11e55e13ce28" + "0d00ee4d43b25d3eca5d41435d423e4e00a01e4e271a00203801003a42716c19" + "5c574d0c7e4d007f4e4fa21b20111e01db0d0e0042680d00465d38375d1d8d4d" + "28f54d60004e929c995c614d26205d36d45d2e7a4d64da4d01f55d3aa85e0076" + "9f4c1e4e258e980d000b4e06e3880d00fa5e02c6614c235d409d4d7a915e06f3" + "3d0d00264e7781240d00414e7b888b0d59035e2d69730e0098605d39960d003f" + "4d0f434d2b264d00894e49b0ae4c2f4d12b64d4c594d01814d43cd4d01eb4d02" + "af4d05025d33054d3bff5e40b5735d07355c7e4e2e4c2e5d09425e323a009dd5" + "085e0c56150e007d675d07a75d14af0e001fb24c044d58384d001a5e0d0cb50d" + "00365d08974d06b15db9a45d15ad4d01a34e0149410e00798a0e002fb94c5b5e" + "10c3c44cb44e08adb04c514d8e804d17924e12e3c05c854d7d474d42394d4de2" + "4d24fa4e0896375d984d5c644eb257394dcb5fae1f99c60d00a44d9d834e1832" + "b70e0082550d03414d11064d57c95d12724e1de6da5d1a765c674d6e224e0351" + "755d0f795c305e6db1544c0b5d500a5e0cbd8e0e0021560d002b4d9a1e4d2ed2" + "5e395b7728fd162a5db7f1297c17034000bb09f0017dbcff9c0302e645a560f4" + "9cbd4c694c000c6c69625831312e736f2e362e332e30f8d77804225420013b0e" + "6b08279917830dba8d5a8a341b01061b498bb45a89442c0e00e98c5c014e0c90" + "de49944b58935a89362f28c80102b2a19e5ef62dca016175a90e3028c8017904" + "f747016aea7727c90180463d721528280102c72bb858f8c90911c80901646d63" + "702f30016105f94601dcff283201945559212728300102664d4b54fad10910d3" + "09657874ad0934282d01685d04fb47011c2778272e0110390204aa7e282c0102" + "d782aa4ffc2d8e0373736909312a5902d8580422a226c6a5282a01d82545e011" + "28280102b5c4a461fec909124d006e0d112f58090866726565626c332e63686b" + "2aa500ff2934042da600736f2aa00074417101162ea00001707269762f590101" + "d5051534b4002868010387d1a85a02022b1005016764626d651f352ae4037d04" + "035e04bfb728e60378e55db87a28e4030312a7bc6104022b1105690213676d96" + "0931312a990005d90413309a002e3228d4016905064b057b327927d4010314b7" + "0700f6c35571b6448465f0b028040275f6072c34030469676678636d72994237" + "2a9d0008dd0414319c002a0c026d05094f050c687c270d0270520cc7c55d0f04" + "28c4280251d18e5a0a5f04de317d279e00b0fd061c301d0a0776de289c007933" + "0b5f04842d7f279c0003f8d11700c5fa04904512aa21562053fe21b42146a063" + "bd500321f62b45ce449e5599ab55da05468b076f2c3d010c5f09098688273e01" + "4c970204ef040a07163b286c040247d30a5a0d2ccc0305706970656c696e65bd" + "5c3528cc036d050e4f050ec689274d0100563d0774283d01805d220f303e0177" + "690f992d302e6e4c2e302aad0010cd051a35af002e3333952eed27c500114706" + "153a8a28be093a0c0535e75db2f8217d3105409721ed245f5ea8f05e4daf122c" + "2506124f076d398f27ee00e4454dc2232c8d00134e04ea5c288d00c456951317" + "2c6505144e04fd73288e00a80a0d341142a72562282404023a54de5e152c420b" + "737102017465c31b382e36e80a6905164b0533dc90274a01acd402ff86330a07" + "f53e59ca480e0008490e00bd435140410e00182521582e214a23f7b82c590217" + "4f0802199b283c13018b05003e49e7db5ebbd29628690216416818c9130ea813" + "0276612d64728d6d322a9500192c2807299400012e3930302860066d051a4f05" + "edc29d27f501c04aa080122cd5011b2fd701676c782fd5011c2fd401f40430d5" + "011d693ad528d5016c5ae8a7282cd6011e0228e015bc09047761796c616e642f" + "e5011fc5051833a40030f501205e0514fe28f501a421b22c5d1d2cf501212fcd" + "0378acf32be501222fcc03f40430d501234f05711b9e27d601e06651cd2e2cd5" + "0124dd090afc092fc501252c4814c40430b501265e046a4a28b6017006061131" + "e021f1244428c401028b832b5b272c9317786362a588312804117904285b04e8" + "6e9f285512a60204afb321dd32322c310b2a725955a0279e0083038d00012a8d" + "002b4e048558288d00a44a4eb90e2c1d012c4e043e673c1d012d4e04c16a288c" + "00035c560b0095ec581e55a5e4210d42b8219e35fd90218d35652c6d012e5f06" + "5e37a627dc00030471060047d941506f090861213e298f142cbd002f5f053c55" + "a93b2d02307de958288e008c27010896210e43286c2c2d01315f047db5aa3b2d" + "01324e0400b9288c000214ba0400214ea432d021ad46342c8e422902287c2902" + "da00f809f0297c407dae3443033fc3ac272d01d44ea7441c2c8d00354e0483df" + "288e0040260a0686632c8d003676d243ad278d002c46f6354e2c8d00376d3691" + "288e000c470d2d5f214e3b90c94d13112cad00384f05075faf28ac005d099c2d" + "3d01394e04a3ad288e0048964db5ac2c8d003a4f04c859b028ec024a797b1e2c" + "8d003b4e044378288d000421ee3b4a462c8d003c4e048dbe288d00544e04b343" + "2c8d003d4f044002b1278d00f44ecc8c162c8d003e4e04cc18288e00d4a541c5" + "3d2c8d003f4e040656288e00c0d60180794e2416952c9d00405f0495b4b2279e" + "0098170da9fa216621d8e24c3121ce3fc30a2cbd004172d12fb527bd00244e2a" + "1c4a2c8d00424e044f79288d00945e1c09472c8d00434f0458c0b52b4a184914" + "2c8d00444e04a1d4288d00145e292f212c8d00454e04d0f5288e0084e60e3922" + "645df79a2c9d00466e58f4b62804255e2a67172c8d00474f043d0cb728a01d4e" + "12cd102c8d00484e040a1d288d00145e1f74402c8d00494f047e5db72b7e0693" + "39284d0d314d6a33294c0d018b03cf0a2e4d0d4c42031197280c0103d88d0900" + "4ef35c1a5d7dae4e0e0dc54d91422c4d014b294c01032d00570e4a022c4d014e" + "5f015a39bb287d24a60a06d38c2c0d014d290f012b00812f0d01505e012dc628" + "0d018c22fd3d802c0d014f2b1d02a92f0d01525f01aa46bc270d017c4e19bd60" + "2c0d0151290f012800d32f0d01545e0167a7280d01dc4e8e0b222c8d00554e04" + "72c9288d00185e1da4bf2c9d0153299f013e00f82f9d01575f011689bd28be07" + "86014c9d2c0d0156290d012505c70f2e0d01595f01554cbe284d28950a0662af" + "2c0d01582bcd04552f0d015b5e01b7fb280d01fc4eb53f7a2c0d015a2b0d017f" + "2f0d015d5f01f675bf28b53dd55d7b662c0d015c290f012700a98c082a7d004a" + "dd030b5d01a907c70ff0012cad18f0252d42065c0101060573102a2c59027cfb" + "655b5f5e07b9dc280e0268364d5a1d28fc1a6d04604e049dfa288e00b09b0104" + "81219e54872b2858217d04612c5821026d616e2d3200cf22142d2a3901625b04" + "a53ac128e8045a8374302c2a0163022b90414a0964622730012aa10064c1050d" + "4f002e2e2f48000162696e2f5c052a9103655204196b28c50138521cd81a2cc5" + "016629f0022b220164622a2901675a04f1852829010821ae561a622cfd5e5e29" + "cc0602a9007615a3295c62028ee74f586a42030be8280c015b88006d00288c00" + "02d39fc85a6b4d0478298e0053075915042c9d0169299c01032f001c1668022c" + "7d0068dd03035c01021f004816a32d6d08a3cd43085c01027b0064167a2d6d08" + "6d5e077bec280d02f05eafa70f2c8d016c290f021f00dccc0828114b70420322" + "fc280e015da45dab2e2c8d00734f04ad2ac2278c004f410009002c8d00744d04" + "b6298d00546c192dad01756d722b288d00b85d01a92dcd037229bc02034200f8" + "1671022c0d01775e01602d280d018e21fe5cc70e2c8d007870074000ed04002d" + "ad0279353c032a1d02762b1e0237172e1d027b5e01273c280d01634503042dbd" + "037c4e042b3d288d00554503062d8d007d4e04313e288d00cd524106022c2d02" + "7a2b2d02762f2d027e5e013740280d01ea4ed4dc182c8d00804e041359288c00" + "223d2b7d2d2d02813ddd04822002dd047f2bad02b52fad02845e01905a280d01" + "8d21927037432c8d00853d1d028620021d02832b1d02f42f1d02885e01c79d28" + "0e01fcbf05d9dd218d6df821dd2179216d5e34219e5a9e202ccd00894f06e7b3" + "c327cd005a4503052d0d058a4e04ecb4288d009e4e1075042c6d02872b6e0233" + "182e6d028c5e0161b9280e018f8d4d4d192c8d008d3d8d048e20028d048b2b1d" + "02722f1d02905e0188d2281d026a45030b2dbd03914e0493d3288d005c45030c" + "278c00110000" + ), + False, + 8192, + "efcff6f6fddf392a7d63966d2441accb27a62d61fe9aa57c5cb521d75e871f0c", + ), + ( + bytes.fromhex("f0000000041574657374110000"), + True, + -1, + "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", + ), + ], + ids=["basic", "large", "larger", "header"], +) +def test_lzo_decompress(lzo: ModuleType, data: bytes, header: bool, buflen: int, digest: str) -> None: + assert hashlib.sha256(lzo.decompress(data, header, buflen)).hexdigest() == digest def test_lzxpress_huffman_decompress() -> None: