IMPORT: slz/uslz: don't lose the bytes consumed by the header fast paths
The format autodetection in uslz_decode() has a fast path for the common
case where the first call carries enough data to parse the header directly
from the caller's buffer, and a slow path that accumulates the header into
hdr_detect.buf across calls. The fast path consumes bytes from the caller's
buffer *before* it knows whether it will be able to complete, and it had no
way to give them back, so three things went wrong:
1) Raw deflate (rfc1951) streams were losing their first two bytes. The
fast path consumes two bytes to sniff the magic, and the fallback that
feeds them back to the block decoder is guarded by "else if (buf_len)",
which is false on exactly that path. Every raw stream fed more than 2
bytes at a time therefore failed with E_CORRUPT (or E_INVALID_BLOCK_CODE,
depending on what the two lost bytes happened to decode as), i.e. raw
deflate was simply unusable:
./zdec < raw.deflate -> error (14)
This is fixed by rewinding in_ptr to the start of the header, which
also lets the fast path skip the local copy the accumulating path
needs.
2) A gzip stream whose first call carried 3 to 9 bytes was mis-parsed.
That is more than 2, so the fast path consumed the magic, but less
than 10, so the 10-byte header could not be parsed, and it fell back
to need_more_header, which starts filling hdr_detect.buf at buf_len=0,
dropping the two bytes already consumed. The next call then parsed the
header two bytes too far. This is fixed by rewinding before the
fallback.
3) The tests on the remaining input used <compressed_size>, which is only
decremented by the fast paths and never by the accumulating ones, so it
overstates what is left in the caller's buffer as soon as the two are
mixed. "if (compressed_size >= 2)" and "if (compressed_size >= xlen)"
could therefore both succeed with fewer bytes actually available, read
the FEXTRA length or payload **past in_top** and advance in_ptr beyond
it. Fixed by testing state->in_top - state->in_ptr, which is exact on
every path; <compressed_size> is no longer modified.
tests/uslztest.sh goes from 1108/1514 to 1438/1514, and raw, gzip, zlib
and slz streams now decode correctly at every input chunk size from 1 to
24 and beyond, for every supported ring size. The gzip variant carrying
FEXTRA is still broken at some chunk sizes, this is for a future fix.
This is libslz upstream commit
cea782efdd111bf476b625051fe4d37cf28be92d