One predicate for the noise offer and one place that allocates the
session; the window is already zero from value initialization, so drop
the second clearing pass. The RP2 backend reads the framework version
from the define ESPHome already emits rather than a vendor header, the
inflate counter moves into the test device helper, and the corrupt
stream sweep takes a coarser stride for the same coverage.
With raw lwIP in the main loop the radio is deaf while a sector is written,
so the ESP8266 and RP2040 keep the client quiet until the block is in flash;
with BSD or lwIP sockets the next block can arrive while this one is written.
Chunk acks again mean the block is in flash on both paths: the read callback
writes and acks everything decoded so far before it waits for more input.
The decoder rejects a negative distance symbol, initialises its whole state,
and the flush feeds the watchdog once per window. The static_assert on the
backend skips the static analysis build, which sets every define at once.
Measured on ESP32: the decoder is 1472 B at -Os and cannot shrink without
dropping dynamic Huffman; the glue loses its extra log sites and strings,
the flash-write log is shared, and the single-call helpers inline on the
platforms without the decoder so the ESP8266 and RP2040 images do not grow.
supports_compression() is constexpr so the deflate build asserts that its
backend cannot store gzip.
The Arduino Pico OTA stub already detects a gzip firmware.bin on LittleFS,
reads the inflated length from the trailer and inflates it into the app
region at reboot, so the RP2040 takes the ESP8266 path and no longer needs
the on-the-fly decoder.
ESP32, RP2040, LibreTiny and host could not receive a compressed image;
only the ESP8266 can, because its bootloader inflates a gzip file at reboot.
This inflates a raw deflate stream on the fly through a 4 KB ring window that
also serves as the output buffer, so the device never holds the whole image.
The CLI offers a new client feature bit; a device whose backend has no gzip
support and has the inflater compiled answers with a new server bit once the
session memory is in hand, then the CLI sends a 4 KB window deflate stream and
the MD5 of the inflated image. On allocation failure the device declines the
bit and the upload stays uncompressed. Old CLIs and old devices never set the
bits, so both directions stay compatible; the ESP8266 keeps its gzip path and
the CLI prefers gzip when a device offers both.
The decoder is uzlib's tinflate.c (zlib licence) trimmed to raw deflate.