"""Pinned Google Zopfli helpers for static and host-generated DEFLATE data. Zopfli writes standards-compliant DEFLATE streams, so the existing device decoders need no additional firmware code or RAM. It is deliberately used only where compression happens on a development machine or host controller: firmware assets, test vectors, and BLE mOTA transport blocks. """ from __future__ import annotations ZOPFLI_VERSION = "0.4.3" try: import zopfli from zopfli import gzip as _gzip from zopfli import zlib as _zlib except ImportError as error: raise RuntimeError( "Google Zopfli 0.4.3 is required to generate MeshCore compressed " "assets. Install it with 'python -m pip install -r " "requirements-build.txt'." ) from error if zopfli.__version__ != ZOPFLI_VERSION: raise RuntimeError( "MeshCore requires Google Zopfli %s, but %s is installed. Run " "'python -m pip install -r requirements-build.txt'." % (ZOPFLI_VERSION, zopfli.__version__) ) # Above zlib's maximum level 9: Zopfli refines the LZ77 model repeatedly. # Fifteen iterations remains the practical default for raw OTA streams. # Firmware HTML gzip assets use the 1,000-iteration setting below. ITERATIONS = 15 # Zopfli has no finite algorithmic iteration ceiling. Its ``--i1000`` # convention is the maximum-effort setting used for host-cached mOTA transfer # blocks, where the extra host CPU time is preferable to wasting radio airtime. MAXIMUM_ITERATIONS = 1000 def _options(numiterations: int = ITERATIONS) -> dict[str, int | bool]: if numiterations < 1: raise ValueError("Zopfli requires at least one iteration") return { "numiterations": numiterations, "blocksplitting": True, "blocksplittinglast": False, "blocksplittingmax": 15, } def gzip_compress(data: bytes, *, numiterations: int = MAXIMUM_ITERATIONS) -> bytes: """Compress *data* as deterministic RFC 1952 gzip using Google Zopfli.""" encoded = bytearray(_gzip.compress(data, **_options(numiterations))) # The gzip OS byte is informational. Normalize it to RFC 1952's unknown # value so a checked-in asset is identical across operating systems. if len(encoded) < 10 or encoded[:3] != b"\x1f\x8b\x08": raise RuntimeError("Zopfli returned an invalid gzip stream") encoded[9] = 0xFF return bytes(encoded) def raw_deflate_compress(data: bytes, *, numiterations: int = ITERATIONS) -> bytes: """Compress *data* to an RFC 1951 raw-DEFLATE stream with Zopfli.""" encoded = _zlib.compress(data, **_options(numiterations)) # A zlib wrapper is exactly a two-byte header and four-byte Adler-32 # trailer. Removing it preserves the RFC 1951 body expected by tinf. if len(encoded) < 6 or (encoded[0] & 0x0F) != 8: raise RuntimeError("Zopfli returned an invalid zlib stream") return encoded[2:-4]