Skip to content

rw2: support raw format 8 (V8), fix panic on undersized raw sections - #60

Open
akilegaspi wants to merge 2 commits into
pedrocr:masterfrom
akilegaspi:fix/rw2-oob-panic
Open

akilegaspi wants to merge 2 commits into
pedrocr:masterfrom
akilegaspi:fix/rw2-oob-panic

Conversation

@akilegaspi

@akilegaspi akilegaspi commented Sep 30, 2026 •

Copy link
Copy Markdown

Fixes #59.

Summary

Adds support for Panasonic RW2 raw format 8 (V8) — the Huffman-coded strip encoding written by the S5 II / S5 II X / S1R II / G9 II generation — and fixes the out-of-bounds panic these files triggered in the legacy decode_panasonic path:

thread '<unnamed>' panicked at rawloader-0.37.2/src/decoders/rw2.rs:94:21:
range start index 26673152 out of range for slice of length 25587216

Changes

1. Generation validation before decoding. The RawFormat tag (0x002d) is read before any pixel decoding and selects the decoder:

  • 8 → the new V8 decoder
  • 4..=7 or tag absent → the legacy decoders, unchanged
  • anything else → a clean Err("RW2: unsupported raw format version …")

2. V8 decoder (port of rawspeed's PanasonicV8Decompressor, LGPL-2.1 — V8 is lossless-JPEG-style prediction over strips of 2×2 CFA tiles):

  • MSB-first bit pump with per-byte bit reversal (RevMsbPump)
  • 16-bit Huffman lookup table built from the in-file code table (note: not a prefix code — first match wins)
  • per-strip decoding from the 2×2 initial prediction in the metadata, predictor reset to the first tile of each row group
  • all V8 tags validated up front: identity gamma curve, zero shift-down, clip value 0xffff, consistent strip tables, tile grid covering the whole image, in-bounds strip data — anything unexpected returns a descriptive Err instead of decoding garbage or panicking

3. Safety net for legacy paths. panasonic_min_buf_size() guards both decode_panasonic call sites: the bound is the block-aligned bit-pump offset of the last row group, strictly below the size of any working 9/8-packed file, so no file that decodes today can be rejected.

4. Camera entries for DC-S5M2 / DC-S5M2X (blackpoint 512, whitepoint 16383, RGGB, rawspeed color matrix).

Verification

  • Panasonic DC-S5M2X files (6008×4008, RawFormat 8, ~1.07 bytes/pixel raw sections) previously panicked; they now decode cleanly with sane levels (min ≈ blackpoint, max = whitepoint) and 0.87 normalized correlation with macOS ImageIO's native decode of the same file (raw Bayer vs. demosaicked render, so <1.0 is expected). Reproduction details in Panic in RW2 decoder (decode_panasonic) on newer Panasonic compression variants #59.
  • cargo test passes (5 passed, 2 ignored).

decode_panasonic computes bit-pump block offsets assuming the classic
9/8-bytes-per-pixel Panasonic packing. Newer bodies (S5 II / S5 II X /
S1R II / G9 II generation) write a ~1 byte/pixel compression, so the
raw section is ~25% smaller than the assumed packing and the unguarded
slice at the top of each row group panics on the rayon decode threads:

  range start index 26673152 out of range for slice of length 25587216

Add a minimum-size guard at both decode_panasonic call sites, computed
from the block-aligned offset of the last row group, so these files
return a descriptive Err instead. The bound is strictly below the size
of any working 9/8-packed file, so existing decodes are unaffected.

Verified with a DC-S5M2X file (6000x4008): previously panicked, now
returns Err("RW2: raw section is 25587216 bytes, too small for
6008x4008; unsupported compression variant").

Fixes pedrocr#59
Port of rawspeed's PanasonicV8Decompressor (LGPL-2.1). V8 files carry a
RawFormat tag (0x002d) that is now checked before decoding to select the
decoder generation:

- RawFormat 8: Huffman-coded strips of 2x2 CFA tiles (lossless-JPEG-like
  prediction). All V8 tags are validated up front: identity gamma curve,
  zero shift-down, clip value 0xffff, consistent strip tables, grid tiling
  covering the whole image, and in-bounds strip data. Anything unexpected
  returns a descriptive Err instead of decoding garbage.
- RawFormat 4..=7 or tag absent: legacy decoders, with the undersized-buffer
  guard from the previous commit kept as a safety net.
- Any other version: clean Err.

The strip bitstream is MSB-first with the bits of each byte reversed; each
strip starts from the 2x2 initial prediction in the metadata and each
symbol is a difference category plus JPEG-style extended diff bits.

Also adds camera entries for DC-S5M2 / DC-S5M2X (blackpoint 512,
whitepoint 16383, RGGB, rawspeed color matrix).

Verified against DC-S5M2X files (6008x4008, RawFormat 8): decode succeeds
with sane levels (min ~= blackpoint, max = whitepoint) and a normalized
correlation of 0.87 with macOS ImageIO's native decode of the same file
(raw Bayer vs. demosaicked render, so <1.0 is expected).
@akilegaspi akilegaspi changed the title rw2: error out instead of panicking on undersized raw sections rw2: support raw format 8 (V8), fix panic on undersized raw sections Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Panic in RW2 decoder (decode_panasonic) on newer Panasonic compression variants

1 participant