Repository navigation
fix(xz): decode compressed LZMA2 chunks as their bytes arrive - #150
Merged
Merged
Conversation
Trigger: an xz stream cut short inside a compressed LZMA2 chunk, or any stream fed to `decode` in pieces smaller than a chunk. Effect: a compressed chunk (up to 64 KiB of input, 2 MiB of output) was only decoded once all of its bytes were buffered. A truncated stream lost the whole chunk it was cut in: a 4 MB file cut 40 bytes short gave 2,096,914 bytes where `xz -dc` gives 3,968,329. Streaming callers also got no output from a chunk until its last byte arrived. Fix: decode packets as the compressed bytes arrive, like liblzma. While the chunk is incomplete, a packet is decoded only if at least 21 unread bytes are buffered (liblzma's LZMA_IN_REQUIRED, the most input one packet can read), so it never runs out of input halfway and leaves the coder state half-updated. Once the chunk is complete it decodes to the end. At `finish` on a stream cut inside a chunk, one last pass decodes every packet the bytes hold. A packet writes nothing until it has been read in full, so all output before the cut is delivered, then UnexpectedEnd. New `LzmaCore::decode_partial`; `decode_chunk` wraps it. Verified: truncated output equals `xz -dc`'s, byte for byte, at 4 cut points in each of 4 streams (2 MiB chunks of zeros, a binary, x86 BCJ, SHA-256 multi-block). Full-stream decode speed is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MagicalTux
force-pushed
the
fix/xz-partial-chunk
branch
from
October 22, 2026 18:38
e775052 to
17b319e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebased onto master after #149 merged; this is now the single partial-chunk commit.
Problem
A compressed LZMA2 chunk (up to 64 KiB of input, 2 MiB of output) was only decoded once all of its bytes were buffered.
xz -dcgives 3,968,329.Fix
Packets are now decoded as the compressed bytes arrive, the way liblzma does it.
LZMA_IN_REQUIRED, the most input one packet can read: at most 22 probability-coded bits (each shrinks the range by at most about 6.05 bits) plus 26 direct bits, so 159 bits, read one byte per 8 bits of shrink, plus one. A packet therefore never runs out of input halfway and leaves the coder state half-updated.finishon a stream cut inside a chunk, one last pass decodes every complete packet the bytes hold. A packet writes nothing until it has been read in full, so every byte before the cut is delivered, and thenUnexpectedEndis returned.LzmaCore::decode_partialis new;decode_chunknow wraps it.Verification
xz -dc: truncated output matches byte for byte at 4 cut points in each of 4 streams: 2 MiB chunks of zeros, a binary, an x86 BCJ stream, and a SHA-256 multi-block stream.xztool needed: half of a compressed chunk already yields output when fed in 1-, 100- and whole-piece slices, and cuts inside a chunk recover more than the complete chunks hold, with any buffer size. Whenxzis installed, the second test also compares againstxz -d. Both tests fail on master.cargo test --features all: 1925 passed. clippy (-D warnings,alland--all-features) and fmt are clean.Not changed
The raw
lzma2decoder (src/lzma2) still decodes whole chunks. It can use the samedecode_partial, as a follow-up.🤖 Generated with Claude Code