Skip to main content

flashraw_codecs/
x3f.rs

1//! Sigma / Foveon X3F entropy coders.
2//!
3//! X3F raw images come in three families:
4//!
5//! - **TRUE** (DP1/DP2/SD14/SD15 "TRUE I/II", Merrill "TRUE II", Quattro "TRUE III"):
6//!   each of the three sensor layers is an independent bit stream (planes start at
7//!   16-byte aligned offsets) coded with one shared prefix code whose symbols are
8//!   the bit length of a JPEG-style difference. Prediction works on 2x2 phases: the
9//!   first two columns of a row predict from the same phase two rows above, all
10//!   other samples from the same phase two columns to the left. Planes decode in
11//!   parallel; within a plane the stream is strictly sequential.
12//! - **Huffman 10-bit** (SD9/SD10/SD14, Polaroid x530): interleaved R,G,B
13//!   difference codes per row (independent rows via a row-offset table), each
14//!   symbol mapped through a 1024-entry difference table. Running sums are 16-bit
15//!   signed; if any sum goes negative the whole image is offset so the minimum is
16//!   zero.
17//! - **Uncompressed "simple"** variant of the above: one 32-bit word per pixel
18//!   holding three 10-bit mapping-table indices.
19//!
20//! Prefix codes in X3F are not canonical (they are given as explicit codes), so
21//! [`PrefixCode`] builds a binary tree plus a 12-bit lookup table on top of it.
22
23use flashraw_core::bits::{BitPumpMsb, BitRead};
24use flashraw_core::{Error, Result};
25
26const LUT_BITS: u32 = 12;
27const NONE: u32 = u32::MAX;
28
29// LUT entry layout: bits 0..5 length, bits 6..8 kind, bits 8..32 payload (value or node index).
30const KIND_LEAF: u32 = 1 << 6;
31const KIND_NODE: u32 = 2 << 6;
32const KIND_MASK: u32 = 3 << 6;
33
34/// A (possibly non-canonical, possibly incomplete) binary prefix code.
35#[derive(Debug, Clone)]
36pub struct PrefixCode {
37    /// Tree nodes: `[child0, child1]`, `NONE` when absent.
38    nodes: Vec<[u32; 2]>,
39    /// Leaf value per node (`NONE` for internal nodes).
40    values: Vec<u32>,
41    lut: Vec<u32>,
42}
43
44impl PrefixCode {
45    /// Build from `(code, length, value)` triples; `code` is right-aligned.
46    pub fn new(codes: &[(u32, u32, u32)]) -> Result<Self> {
47        let mut nodes = vec![[NONE, NONE]];
48        let mut values = vec![NONE];
49        for &(code, len, value) in codes {
50            if len == 0 || len > 27 {
51                return Err(Error::corrupt(format!("X3F prefix code with invalid length {len}")));
52            }
53            if value >= 1 << 24 {
54                return Err(Error::corrupt("X3F prefix code value out of range"));
55            }
56            let mut n = 0usize;
57            for i in (0..len).rev() {
58                let bit = ((code >> i) & 1) as usize;
59                let next = nodes[n][bit];
60                n = if next == NONE {
61                    nodes.push([NONE, NONE]);
62                    values.push(NONE);
63                    let idx = nodes.len() - 1;
64                    nodes[n][bit] = idx as u32;
65                    idx
66                } else {
67                    next as usize
68                };
69            }
70            values[n] = value;
71        }
72        if nodes[0] == [NONE, NONE] {
73            return Err(Error::corrupt("X3F prefix code without codes"));
74        }
75        let mut code = PrefixCode { nodes, values, lut: Vec::new() };
76        code.build_lut();
77        Ok(code)
78    }
79
80    /// Walk the code with the `nbits` most significant bits of `prefix` (left-aligned in
81    /// `nbits`): `(code length, value)` if a leaf is reached within them.
82    pub fn walk(&self, prefix: u32, nbits: u32) -> Option<(u32, u32)> {
83        let mut n = 0usize;
84        for len in 0..=nbits {
85            if self.is_leaf(n) {
86                return (self.values[n] != NONE).then_some((len, self.values[n]));
87            }
88            if len == nbits {
89                break;
90            }
91            let next = self.nodes[n][((prefix >> (nbits - 1 - len)) & 1) as usize];
92            if next == NONE {
93                return None;
94            }
95            n = next as usize;
96        }
97        None
98    }
99
100    fn is_leaf(&self, n: usize) -> bool {
101        self.nodes[n] == [NONE, NONE]
102    }
103
104    fn build_lut(&mut self) {
105        let mut lut = vec![0u32; 1 << LUT_BITS];
106        for (idx, e) in lut.iter_mut().enumerate() {
107            let mut n = 0usize;
108            let mut len = 0;
109            *e = loop {
110                if self.is_leaf(n) {
111                    // A terminal node without a value is an unusable code.
112                    break if self.values[n] == NONE { 0 } else { len | KIND_LEAF | (self.values[n] << 8) };
113                }
114                if len == LUT_BITS {
115                    break LUT_BITS | KIND_NODE | ((n as u32) << 8);
116                }
117                let bit = (idx >> (LUT_BITS - 1 - len)) & 1;
118                let next = self.nodes[n][bit];
119                if next == NONE {
120                    break 0;
121                }
122                n = next as usize;
123                len += 1;
124            };
125        }
126        self.lut = lut;
127    }
128
129    /// Decode one symbol.
130    #[inline(always)]
131    pub fn decode<B: BitRead>(&self, bits: &mut B) -> Result<u32> {
132        bits.fill();
133        let e = self.lut[bits.peek_no_fill(LUT_BITS) as usize];
134        match e & KIND_MASK {
135            KIND_LEAF => {
136                bits.skip_no_fill(e & 0x3F);
137                Ok(e >> 8)
138            }
139            KIND_NODE => {
140                bits.skip_no_fill(LUT_BITS);
141                self.decode_slow(bits, (e >> 8) as usize)
142            }
143            _ => Err(Error::corrupt("invalid X3F prefix code")),
144        }
145    }
146
147    #[cold]
148    fn decode_slow<B: BitRead>(&self, bits: &mut B, mut n: usize) -> Result<u32> {
149        while !self.is_leaf(n) {
150            let next = self.nodes[n][bits.get(1) as usize];
151            if next == NONE {
152                return Err(Error::corrupt("invalid X3F prefix code"));
153            }
154            n = next as usize;
155        }
156        match self.values[n] {
157            NONE => Err(Error::corrupt("invalid X3F prefix code")),
158            v => Ok(v),
159        }
160    }
161}
162
163/// Parsed header of a TRUE-engine raw image section (after the 28-byte image header).
164#[derive(Debug, Clone)]
165pub struct TrueHeader {
166    /// Quattro plane sizes `(columns, rows)` (bottom, middle, top) when present.
167    pub planes: Option<[(u32, u32); 3]>,
168    pub seeds: [u16; 3],
169    /// `(code_size, code)` pairs; the symbol of entry `i` is `i` (the diff bit length).
170    pub table: Vec<(u8, u8)>,
171    pub plane_sizes: [u32; 3],
172    /// Offset of the first plane's data within the parsed slice.
173    pub data_offset: usize,
174}
175
176fn rd16(d: &[u8], p: &mut usize) -> Result<u16> {
177    let b = d.get(*p..*p + 2).ok_or_else(|| Error::corrupt("truncated X3F TRUE header"))?;
178    *p += 2;
179    Ok(u16::from_le_bytes([b[0], b[1]]))
180}
181
182fn rd32(d: &[u8], p: &mut usize) -> Result<u32> {
183    let b = d.get(*p..*p + 4).ok_or_else(|| Error::corrupt("truncated X3F TRUE header"))?;
184    *p += 4;
185    Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
186}
187
188impl TrueHeader {
189    /// Parse from the image payload (the bytes following the 28-byte `SECi` header).
190    pub fn parse(d: &[u8], quattro: bool) -> Result<Self> {
191        let mut p = 0usize;
192        let planes = if quattro {
193            let mut pl = [(0u32, 0u32); 3];
194            for e in pl.iter_mut() {
195                let c = rd16(d, &mut p)? as u32;
196                let r = rd16(d, &mut p)? as u32;
197                *e = (c, r);
198            }
199            Some(pl)
200        } else {
201            None
202        };
203        let seeds = [rd16(d, &mut p)?, rd16(d, &mut p)?, rd16(d, &mut p)?];
204        let _unknown = rd16(d, &mut p)?;
205        let mut table = Vec::new();
206        loop {
207            let b = d.get(p..p + 2).ok_or_else(|| Error::corrupt("truncated X3F TRUE code table"))?;
208            p += 2;
209            table.push((b[0], b[1]));
210            if b[0] == 0 {
211                break;
212            }
213            if table.len() > 256 {
214                return Err(Error::corrupt("X3F TRUE code table too long"));
215            }
216        }
217        if quattro {
218            let _unknown = rd32(d, &mut p)?;
219        }
220        let plane_sizes = [rd32(d, &mut p)?, rd32(d, &mut p)?, rd32(d, &mut p)?];
221        Ok(TrueHeader { planes, seeds, table, plane_sizes, data_offset: p })
222    }
223
224    /// The decoding table for the planes.
225    pub fn table(&self) -> Result<TrueTable> {
226        Ok(TrueTable::new(self.code()?))
227    }
228
229    /// The prefix code (symbol = diff bit length).
230    pub fn code(&self) -> Result<PrefixCode> {
231        true_code(&self.table)
232    }
233
234    /// Byte ranges `(start, end)` of each plane within `data` (relative to the data start).
235    /// A plane's stream may legally run into the following plane's padding, so `end` is
236    /// the end of all image data.
237    pub fn plane_ranges(&self, data_len: usize) -> Result<[(usize, usize); 3]> {
238        let mut out = [(0usize, data_len); 3];
239        let mut off = 0usize;
240        for (i, &s) in self.plane_sizes.iter().enumerate() {
241            out[i].0 = off;
242            off = off
243                .checked_add((s as usize).div_ceil(16) * 16)
244                .ok_or_else(|| Error::corrupt("X3F TRUE plane sizes overflow"))?;
245        }
246        if off > data_len {
247            return Err(Error::corrupt("X3F TRUE planes exceed section size"));
248        }
249        Ok(out)
250    }
251}
252
253/// Prefix code of a TRUE-style `(code_size, code)` table: the symbol of entry `i` is `i`
254/// (the bit length of the difference that follows), codes are left-aligned in a byte.
255fn true_code(table: &[(u8, u8)]) -> Result<PrefixCode> {
256    let codes: Vec<(u32, u32, u32)> = table
257        .iter()
258        .enumerate()
259        .filter(|(_, (len, _))| *len != 0)
260        .map(|(i, &(len, code))| {
261            let len = len as u32;
262            let c = if len <= 8 { (code as u32 >> (8 - len)) & 0xFF } else { u32::MAX };
263            (c, len, i as u32)
264        })
265        .collect();
266    if codes.iter().any(|&(c, _, _)| c == u32::MAX) {
267        return Err(Error::corrupt("X3F TRUE code longer than 8 bits"));
268    }
269    PrefixCode::new(&codes)
270}
271
272const TT_BITS: u32 = 14;
273const TT_FULL: u32 = 1 << 6;
274const TT_VALID: u32 = 1 << 7;
275
276/// TRUE-engine decoding table: one probe yields the code *and* its difference bits
277/// whenever both fit in `TT_BITS` (almost always), falling back to the tree.
278#[derive(Debug, Clone)]
279pub struct TrueTable {
280    lut: Vec<u32>,
281    code: PrefixCode,
282}
283
284#[inline(always)]
285fn extend(v: u32, len: u32) -> i32 {
286    if v >> (len - 1) == 0 { v as i32 - ((1i64 << len) - 1) as i32 } else { v as i32 }
287}
288
289impl TrueTable {
290    pub fn new(code: PrefixCode) -> Self {
291        let lut = (0..1u32 << TT_BITS)
292            .map(|idx| match code.walk(idx, TT_BITS) {
293                Some((clen, 0)) => clen | TT_FULL | TT_VALID,
294                Some((clen, sym)) if clen + sym <= TT_BITS => {
295                    let v = (idx >> (TT_BITS - clen - sym)) & ((1 << sym) - 1);
296                    (clen + sym) | TT_FULL | TT_VALID | ((extend(v, sym) as i16 as u16 as u32) << 16)
297                }
298                Some((clen, sym)) if sym <= 31 => clen | TT_VALID | (sym << 8),
299                _ => 0,
300            })
301            .collect();
302        TrueTable { lut, code }
303    }
304
305    /// Decode one difference.
306    #[inline(always)]
307    pub fn diff(&self, bits: &mut BitPumpMsb) -> Result<i32> {
308        bits.fill();
309        let e = self.lut[bits.peek_no_fill(TT_BITS) as usize];
310        if e & TT_FULL != 0 {
311            bits.skip_no_fill(e & 0x3F);
312            return Ok((e >> 16) as u16 as i16 as i32);
313        }
314        let len = if e & TT_VALID != 0 {
315            bits.skip_no_fill(e & 0x3F);
316            (e >> 8) & 0x3F
317        } else {
318            self.code.decode(bits)?
319        };
320        if len == 0 {
321            return Ok(0);
322        }
323        if len > 31 {
324            return Err(Error::corrupt("X3F TRUE difference too long"));
325        }
326        Ok(extend(read_bits(bits, len), len))
327    }
328}
329
330/// Decode one TRUE plane of `cols x rows` samples into `out` (`out_cols` samples per row,
331/// `out_cols <= cols`; extra columns on the right are decoded and discarded).
332#[allow(clippy::needless_range_loop)]
333pub fn decode_true_plane(
334    code: &TrueTable,
335    data: &[u8],
336    seed: u16,
337    cols: usize,
338    rows: usize,
339    out_cols: usize,
340    out: &mut [u16],
341) -> Result<()> {
342    if out_cols > cols || out.len() < out_cols * rows {
343        return Err(Error::corrupt("X3F TRUE plane geometry mismatch"));
344    }
345    let mut bits = BitPumpMsb::new(data);
346    let mut row_start = [[seed as i32; 2]; 2];
347    for (r, orow) in out.chunks_exact_mut(out_cols.max(1)).take(rows).enumerate() {
348        let odd_row = r & 1;
349        let mut acc = [0i32; 2];
350        for col in 0..cols {
351            let diff = code.diff(&mut bits)?;
352            let phase = col & 1;
353            let value = if col < 2 {
354                let v = row_start[odd_row][phase].wrapping_add(diff);
355                row_start[odd_row][phase] = v;
356                v
357            } else {
358                acc[phase].wrapping_add(diff)
359            };
360            acc[phase] = value;
361            if col < out_cols {
362                orow[col] = value as u16;
363            }
364        }
365        if bits.exhausted() {
366            return Err(Error::corrupt("truncated X3F TRUE plane"));
367        }
368    }
369    Ok(())
370}
371
372#[inline(always)]
373fn read_bits<B: BitRead>(bits: &mut B, n: u32) -> u32 {
374    // `fill` guarantees at least 32 buffered bits and `n <= 31`.
375    bits.get(n)
376}
377
378/// Code table of the 10-bit Huffman format: entries are `length << 27 | code`, the
379/// symbol of entry `i` is `mapping[i]` when a full mapping table is present, else `i`.
380pub fn huffman_code(table: &[u32], mapping: &[u16]) -> Result<PrefixCode> {
381    let codes: Vec<(u32, u32, u32)> = table
382        .iter()
383        .enumerate()
384        .filter(|(_, e)| **e != 0)
385        .map(|(i, &e)| {
386            let v = if mapping.len() == table.len() { mapping[i] as u32 } else { i as u32 };
387            (e & 0x07FF_FFFF, (e >> 27) & 0x1F, v)
388        })
389        .collect();
390    PrefixCode::new(&codes)
391}
392
393/// Decode a row-indexed 10-bit Huffman image (3 interleaved colours) into `out`
394/// (`cols * rows * 3` samples). `data` is the entropy-coded area, `row_offsets` the
395/// per-row start offsets into it.
396pub fn decode_huffman(
397    code: &PrefixCode,
398    data: &[u8],
399    row_offsets: &[u32],
400    cols: usize,
401    rows: usize,
402    out: &mut [u16],
403    parallel: bool,
404) -> Result<()> {
405    let rl = cols * 3;
406    if row_offsets.len() < rows || out.len() < rl * rows || rl == 0 {
407        return Err(Error::corrupt("X3F Huffman geometry mismatch"));
408    }
409    let errors = std::sync::Mutex::new(None);
410    let minimum = std::sync::atomic::AtomicI32::new(0);
411    // Pass 1: 16-bit running sums starting at 0, stored as raw two's complement.
412    flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 16, parallel, |first, chunk| {
413        let mut local_min = 0i32;
414        for (i, row) in chunk.chunks_exact_mut(rl).enumerate() {
415            let r = first + i;
416            let off = row_offsets[r] as usize;
417            if off >= data.len() {
418                *errors.lock().unwrap() = Some(Error::corrupt("X3F Huffman row offset out of range"));
419                return;
420            }
421            let mut bits = BitPumpMsb::new(&data[off..]);
422            let mut c = [0i16; 3];
423            for px in row.chunks_exact_mut(3) {
424                for (k, v) in px.iter_mut().enumerate() {
425                    match code.decode(&mut bits) {
426                        Ok(d) => c[k] = c[k].wrapping_add(d as i16),
427                        Err(e) => {
428                            *errors.lock().unwrap() = Some(e);
429                            return;
430                        }
431                    }
432                    local_min = local_min.min(c[k] as i32);
433                    *v = c[k] as u16;
434                }
435            }
436            if bits.exhausted() {
437                *errors.lock().unwrap() = Some(Error::corrupt("truncated X3F Huffman row"));
438                return;
439            }
440        }
441        minimum.fetch_min(local_min, std::sync::atomic::Ordering::Relaxed);
442    });
443    if let Some(e) = errors.into_inner().unwrap() {
444        return Err(e);
445    }
446    // Pass 2: offset everything so the most negative sum becomes 0, clamp negatives.
447    let offset = (-minimum.into_inner()) as i16;
448    flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 64, parallel, |_, chunk| {
449        for v in chunk.iter_mut() {
450            let s = (*v as i16).wrapping_add(offset);
451            *v = if s < 0 { 0 } else { s as u16 };
452        }
453    });
454    Ok(())
455}
456
457/// Decode the uncompressed variant: one little-endian 32-bit word per pixel holding
458/// three `bits`-bit indices into `mapping` (differences), running sums per colour.
459#[allow(clippy::too_many_arguments)]
460pub fn decode_simple(
461    data: &[u8],
462    row_stride: usize,
463    mapping: &[u16],
464    bits: u32,
465    cols: usize,
466    rows: usize,
467    out: &mut [u16],
468    parallel: bool,
469) -> Result<()> {
470    if !(8..=12).contains(&bits) {
471        return Err(Error::corrupt(format!("X3F simple coding with {bits} bits")));
472    }
473    let rl = cols * 3;
474    if row_stride < cols * 4 || out.len() < rl * rows || rl == 0 {
475        return Err(Error::corrupt("X3F uncompressed geometry mismatch"));
476    }
477    let needed = (rows - 1).checked_mul(row_stride).and_then(|v| v.checked_add(cols * 4));
478    if needed.is_none_or(|n| n > data.len()) {
479        return Err(Error::corrupt("truncated X3F uncompressed data"));
480    }
481    let mask = (1u32 << bits) - 1;
482    flashraw_core::par::for_each_row_chunk(&mut out[..rl * rows], rl, 32, parallel, |first, chunk| {
483        for (i, row) in chunk.chunks_exact_mut(rl).enumerate() {
484            let src = &data[(first + i) * row_stride..];
485            let mut c = [0u16; 3];
486            for (px, w) in row.chunks_exact_mut(3).zip(src.chunks_exact(4)) {
487                let val = u32::from_le_bytes([w[0], w[1], w[2], w[3]]);
488                for k in 0..3 {
489                    let idx = ((val >> (k as u32 * bits)) & mask) as usize;
490                    let d = if mapping.is_empty() { idx as u16 } else { mapping.get(idx).copied().unwrap_or(0) };
491                    c[k] = c[k].wrapping_add(d);
492                    px[k] = if (c[k] as i16) > 0 { c[k] } else { 0 };
493                }
494            }
495        }
496    });
497    Ok(())
498}
499
500/// Largest decoded CAMF block accepted (real files hold up to a few MiB).
501pub const CAMF_MAX_DECODED: usize = 64 << 20;
502
503/// Coding state of a [`CamfStream`].
504enum CamfCoding<'a> {
505    /// Fully decoded (type 2, or a finished stream).
506    Done,
507    /// Type 5: running byte sum.
508    Bytes { code: TrueTable, bits: BitPumpMsb<'a>, acc: i32 },
509    /// Type 4: 12-bit samples with 2x2-phase prediction, two per three bytes.
510    Samples {
511        code: TrueTable,
512        bits: BitPumpMsb<'a>,
513        cols: usize,
514        rows: usize,
515        row: usize,
516        col: usize,
517        acc: [i32; 2],
518        row_start: [[i32; 2]; 2],
519        half: Option<i32>,
520    },
521}
522
523/// Incremental decoder of an X3F `SECc` (CAMF calibration) section.
524///
525/// `section` is the whole section starting at its `SECc` signature: a 28-byte header
526/// (signature, version, coding type, four type-specific words) followed by the coded
527/// data. Three codings exist:
528/// - type 2 (SD9 … SD14): bytes XOR-ed with a pseudo-random stream seeded by word 3;
529/// - type 4 (DP1 … Merrill): a TRUE-style prefix code (table at the start of the data,
530///   bit stream at data offset 32) over `block_size x block_count` (words 2 and 3)
531///   12-bit samples with the TRUE 2x2-phase prediction (seed in word 1), packed two
532///   samples per three bytes and cut to the decoded size in word 0;
533/// - type 5 (Quattro): the same code over a running byte sum (seed in word 1), one
534///   symbol per decoded byte (decoded size in word 0).
535///
536/// The decoded block is a sequence of `CMb*` entries. Blocks run to several MiB (mostly
537/// spatial gain and defect tables after the colour calibration), so they are decoded on
538/// demand: [`CamfStream::fill`] extends [`CamfStream::decoded`] as far as needed.
539pub struct CamfStream<'a> {
540    out: Vec<u8>,
541    size: usize,
542    coding: CamfCoding<'a>,
543}
544
545impl<'a> CamfStream<'a> {
546    /// Parse the section header (type 2 blocks are decoded at once).
547    pub fn new(section: &'a [u8]) -> Result<Self> {
548        let word = |i: usize| -> Result<u32> {
549            let b = section.get(i * 4..i * 4 + 4).ok_or_else(|| Error::corrupt("truncated X3F CAMF header"))?;
550            Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
551        };
552        let kind = word(2)?;
553        let w = [word(3)?, word(4)?, word(5)?, word(6)?];
554        let data = &section[28..];
555        if kind == 2 {
556            let mut key = w[3];
557            let out: Vec<u8> = data
558                .iter()
559                .map(|&b| {
560                    key = key.wrapping_mul(1597).wrapping_add(51749) % 244_944;
561                    let tmp = ((key as u64 * 301_593_171) >> 24) as u32;
562                    b ^ ((((key << 8).wrapping_sub(tmp) >> 1).wrapping_add(tmp) >> 17) as u8)
563                })
564                .collect();
565            return Ok(CamfStream { size: out.len(), out, coding: CamfCoding::Done });
566        }
567        if kind != 4 && kind != 5 {
568            return Err(Error::corrupt(format!("unknown X3F CAMF coding {kind}")));
569        }
570        let size = w[0] as usize;
571        // Every symbol takes at least one bit and yields at most 1.5 bytes.
572        if size > CAMF_MAX_DECODED || size > data.len().saturating_mul(12) {
573            return Err(Error::corrupt(format!("invalid X3F CAMF block of {size} bytes")));
574        }
575        let mut table = Vec::new();
576        for pair in data.chunks_exact(2) {
577            if pair[0] == 0 {
578                break;
579            }
580            table.push((pair[0], pair[1]));
581        }
582        let code = TrueTable::new(true_code(&table)?);
583        let bits = BitPumpMsb::new(data.get(32..).ok_or_else(|| Error::corrupt("truncated X3F CAMF data"))?);
584        let coding = if kind == 5 {
585            CamfCoding::Bytes { code, bits, acc: w[1] as i32 }
586        } else {
587            let seed = w[1] as i32;
588            CamfCoding::Samples {
589                code,
590                bits,
591                cols: w[2] as usize,
592                rows: w[3] as usize,
593                row: 0,
594                col: 0,
595                acc: [0; 2],
596                row_start: [[seed; 2]; 2],
597                half: None,
598            }
599        };
600        Ok(CamfStream { out: Vec::new(), size, coding })
601    }
602
603    /// The bytes decoded so far.
604    pub fn decoded(&self) -> &[u8] {
605        &self.out
606    }
607
608    /// True when the whole block is decoded.
609    pub fn is_done(&self) -> bool {
610        matches!(self.coding, CamfCoding::Done)
611    }
612
613    /// Decode until at least `len` bytes (or the whole block) are available.
614    pub fn fill(&mut self, len: usize) -> Result<()> {
615        let target = len.min(self.size);
616        if self.out.len() >= target {
617            return Ok(());
618        }
619        self.out.reserve(target - self.out.len());
620        let out = &mut self.out;
621        let size = self.size;
622        let finished = match &mut self.coding {
623            CamfCoding::Done => return Ok(()),
624            CamfCoding::Bytes { code, bits, acc } => {
625                while out.len() < target {
626                    *acc = acc.wrapping_add(code.diff(bits)?);
627                    out.push(*acc as u8);
628                }
629                if bits.exhausted() {
630                    return Err(Error::corrupt("truncated X3F CAMF data"));
631                }
632                out.len() >= size
633            }
634            CamfCoding::Samples { code, bits, cols, rows, row, col, acc, row_start, half } => {
635                'rows: while *row < *rows {
636                    while *col < *cols {
637                        let d = code.diff(bits)?;
638                        let phase = *col & 1;
639                        let start = &mut row_start[*row & 1][phase];
640                        let v = if *col < 2 { *start } else { acc[phase] }.wrapping_add(d);
641                        acc[phase] = v;
642                        if *col < 2 {
643                            *start = v;
644                        }
645                        *col += 1;
646                        match half.take() {
647                            None => {
648                                out.push((v >> 4) as u8);
649                                *half = Some(v);
650                            }
651                            Some(p) => {
652                                out.push(((p << 4) as u8 & 0xf0) | ((v >> 8) as u8 & 0x0f));
653                                out.push(v as u8);
654                            }
655                        }
656                        if out.len() >= size {
657                            break 'rows;
658                        }
659                        if out.len() >= target {
660                            break;
661                        }
662                    }
663                    if *col >= *cols {
664                        *col = 0;
665                        *row += 1;
666                        *acc = [0; 2];
667                    }
668                    if out.len() >= target {
669                        break;
670                    }
671                }
672                if bits.exhausted() {
673                    return Err(Error::corrupt("truncated X3F CAMF data"));
674                }
675                let finished = out.len() >= size || *row >= *rows;
676                if finished {
677                    if let Some(p) = half.take() {
678                        out.push((p << 4) as u8 & 0xf0);
679                    }
680                    // Blocks with fewer samples than the declared size leave the rest zero.
681                    out.resize(size, 0);
682                }
683                finished
684            }
685        };
686        if finished {
687            self.coding = CamfCoding::Done;
688        }
689        Ok(())
690    }
691}
692
693/// Decode a whole CAMF section (see [`CamfStream`]).
694pub fn decode_camf(section: &[u8]) -> Result<Vec<u8>> {
695    let mut s = CamfStream::new(section)?;
696    s.fill(usize::MAX)?;
697    Ok(s.out)
698}
699
700#[cfg(test)]
701mod tests {
702    use super::*;
703
704    /// MSB-first bit writer for synthetic streams.
705    struct W {
706        out: Vec<u8>,
707        acc: u64,
708        n: u32,
709    }
710    impl W {
711        fn new() -> Self {
712            W { out: Vec::new(), acc: 0, n: 0 }
713        }
714        fn put(&mut self, v: u32, len: u32) {
715            for i in (0..len).rev() {
716                self.acc = (self.acc << 1) | ((v >> i) & 1) as u64;
717                self.n += 1;
718                if self.n == 8 {
719                    self.out.push(self.acc as u8);
720                    self.acc = 0;
721                    self.n = 0;
722                }
723            }
724        }
725        fn finish(mut self) -> Vec<u8> {
726            if self.n > 0 {
727                self.out.push((self.acc << (8 - self.n)) as u8);
728            }
729            self.out.extend_from_slice(&[0; 16]);
730            self.out
731        }
732    }
733
734    // Code: diff lengths 0..=2 -> "00", "01", "10"; lengths 3..=6 -> "11" + 2 bits.
735    fn table() -> Vec<(u8, u8)> {
736        vec![
737            (2, 0b0000_0000),
738            (2, 0b0100_0000),
739            (2, 0b1000_0000),
740            (4, 0b1100_0000),
741            (4, 0b1101_0000),
742            (4, 0b1110_0000),
743            (4, 0b1111_0000),
744            (0, 0),
745        ]
746    }
747
748    fn encode_diff(w: &mut W, d: i32) {
749        let len = if d == 0 { 0 } else { 32 - (d.unsigned_abs()).leading_zeros() };
750        let (code, clen) = [(0, 2), (1, 2), (2, 2), (12, 4), (13, 4), (14, 4), (15, 4)][len as usize];
751        w.put(code, clen);
752        if len > 0 {
753            let v = if d > 0 { d as u32 } else { (d + (1 << len) - 1) as u32 };
754            w.put(v, len);
755        }
756    }
757
758    #[test]
759    fn true_plane_roundtrip() {
760        let (cols, rows, seed) = (7usize, 5usize, 512u16);
761        let img: Vec<i32> = (0..cols * rows).map(|i| 500 + ((i * 7919) % 23) as i32 - 11).collect();
762        let mut w = W::new();
763        let mut row_start = [[seed as i32; 2]; 2];
764        for r in 0..rows {
765            let mut acc = [0i32; 2];
766            for c in 0..cols {
767                let v = img[r * cols + c];
768                let prev = if c < 2 { row_start[r & 1][c & 1] } else { acc[c & 1] };
769                encode_diff(&mut w, v - prev);
770                acc[c & 1] = v;
771                if c < 2 {
772                    row_start[r & 1][c & 1] = v;
773                }
774            }
775        }
776        let data = w.finish();
777        let hdr = TrueHeader {
778            planes: None,
779            seeds: [seed; 3],
780            table: table(),
781            plane_sizes: [data.len() as u32, 0, 0],
782            data_offset: 0,
783        };
784        let code = hdr.table().unwrap();
785        let mut out = vec![0u16; (cols - 1) * rows];
786        decode_true_plane(&code, &data, seed, cols, rows, cols - 1, &mut out).unwrap();
787        for r in 0..rows {
788            for c in 0..cols - 1 {
789                assert_eq!(out[r * (cols - 1) + c] as i32, img[r * cols + c]);
790            }
791        }
792    }
793
794    #[test]
795    fn true_plane_truncated_is_error() {
796        let code = TrueHeader { planes: None, seeds: [0; 3], table: table(), plane_sizes: [0; 3], data_offset: 0 }
797            .table()
798            .unwrap();
799        let data = [0xFFu8; 4];
800        let mut out = vec![0u16; 64 * 64];
801        assert!(decode_true_plane(&code, &data, 0, 64, 64, 64, &mut out).is_err());
802    }
803
804    #[test]
805    fn true_header_parse_and_ranges() {
806        let mut d = Vec::new();
807        for v in [512u16, 512, 512, 0] {
808            d.extend_from_slice(&v.to_le_bytes());
809        }
810        for (l, c) in table() {
811            d.extend_from_slice(&[l, c]);
812        }
813        for s in [17u32, 3, 40] {
814            d.extend_from_slice(&s.to_le_bytes());
815        }
816        let h = TrueHeader::parse(&d, false).unwrap();
817        assert_eq!(h.seeds, [512; 3]);
818        assert_eq!(h.table.len(), 8);
819        assert_eq!(h.data_offset, d.len());
820        assert_eq!(h.plane_ranges(100).unwrap(), [(0, 100), (32, 100), (48, 100)]);
821        assert!(h.plane_ranges(80).is_err());
822        assert!(TrueHeader::parse(&d[..9], false).is_err());
823    }
824
825    #[test]
826    fn prefix_code_long_codes() {
827        // Codes longer than the LUT: 14 ones then 0/1.
828        let codes = vec![(0, 1, 5), ((1 << 14) - 2, 14, 6), ((1 << 15) - 2, 15, 7), ((1 << 15) - 1, 15, 8)];
829        let pc = PrefixCode::new(&codes).unwrap();
830        let mut w = W::new();
831        for &(c, l, _) in &codes {
832            w.put(c, l);
833        }
834        let data = w.finish();
835        let mut b = BitPumpMsb::new(&data);
836        for &(_, _, v) in &codes {
837            assert_eq!(pc.decode(&mut b).unwrap(), v);
838        }
839        assert!(PrefixCode::new(&[]).is_err());
840        assert!(PrefixCode::new(&[(0, 0, 1)]).is_err());
841    }
842
843    #[test]
844    fn huffman_offset_and_clamp() {
845        // Symbols: "0" -> +5, "10" -> -7 (0xFFF9), "11" -> +1.
846        let table: Vec<u32> = vec![(1 << 27), (2 << 27) | 2, (2 << 27) | 3];
847        let mapping = vec![5u16, 0xFFF9, 1];
848        let code = huffman_code(&table, &mapping).unwrap();
849        // Row 0: R:-7 G:+5 B:+1 ; Row 1: R:+5 G:+5 B:+5.
850        let mut w = W::new();
851        let r0 = w.out.len();
852        w.put(0b10, 2);
853        w.put(0, 1);
854        w.put(0b11, 2);
855        w.put(0, 3); // pad to byte boundary
856        let data0 = std::mem::take(&mut w.out);
857        let mut w = W::new();
858        w.put(0, 3);
859        let mut data = data0.clone();
860        data.extend(w.finish());
861        let offs = [r0 as u32, data0.len() as u32];
862        let mut out = vec![0u16; 6];
863        decode_huffman(&code, &data, &offs, 1, 2, &mut out, false).unwrap();
864        // min = -7 -> offset 7.
865        assert_eq!(out, vec![0, 12, 8, 12, 12, 12]);
866    }
867
868    #[test]
869    fn simple_decode() {
870        let mapping: Vec<u16> = (0..1024).map(|i| i as u16).collect();
871        let px = |r: u32, g: u32, b: u32| (r | (g << 10) | (b << 20)).to_le_bytes();
872        let mut data = Vec::new();
873        data.extend_from_slice(&px(10, 20, 30));
874        data.extend_from_slice(&px(1, 2, 3));
875        let mut out = vec![0u16; 6];
876        decode_simple(&data, 8, &mapping, 10, 2, 1, &mut out, false).unwrap();
877        assert_eq!(out, vec![10, 20, 30, 11, 22, 33]);
878        assert!(decode_simple(&data[..6], 8, &mapping, 10, 2, 1, &mut out, false).is_err());
879    }
880
881    /// A `SECc` section: header words then the coded data.
882    fn camf_section(kind: u32, words: [u32; 4], data: &[u8]) -> Vec<u8> {
883        let mut s = b"SECc".to_vec();
884        for w in [0x0002_0000, kind, words[0], words[1], words[2], words[3]] {
885            s.extend_from_slice(&u32::to_le_bytes(w));
886        }
887        s.extend_from_slice(data);
888        s
889    }
890
891    /// Code table padded to the 32 bytes that precede a CAMF bit stream.
892    fn camf_table() -> Vec<u8> {
893        let mut d: Vec<u8> = table().iter().flat_map(|&(a, b)| [a, b]).collect();
894        d.resize(32, 0);
895        d
896    }
897
898    #[test]
899    fn camf_type2_is_its_own_inverse() {
900        let plain: Vec<u8> = b"CMbT entries".iter().copied().cycle().take(300).collect();
901        let coded = decode_camf(&camf_section(2, [0, 0, 0, 0x6149_13eb], &plain)).unwrap();
902        assert_ne!(coded, plain);
903        assert_eq!(decode_camf(&camf_section(2, [0, 0, 0, 0x6149_13eb], &coded)).unwrap(), plain);
904    }
905
906    #[test]
907    fn camf_type5_running_bytes() {
908        let plain: Vec<u8> = (0..500u32).map(|i| (100 + (i * 37 % 41) as i32 - 20) as u8).collect();
909        let bias = 90u32;
910        let mut w = W::new();
911        let mut prev = bias as i32;
912        for &b in &plain {
913            encode_diff(&mut w, b as i32 - prev);
914            prev = b as i32;
915        }
916        let mut data = camf_table();
917        data.extend_from_slice(&w.finish());
918        let section = camf_section(5, [plain.len() as u32, bias, 0, 0], &data);
919        assert_eq!(decode_camf(&section).unwrap(), plain);
920        // Decoded on demand: a partial fill stops early and resumes.
921        let mut s = CamfStream::new(&section).unwrap();
922        s.fill(10).unwrap();
923        assert!(s.decoded().len() >= 10 && s.decoded().len() < plain.len() && !s.is_done());
924        s.fill(usize::MAX).unwrap();
925        assert!(s.is_done());
926        assert_eq!(s.decoded(), &plain[..]);
927        // Truncated data and implausible sizes are errors.
928        assert!(decode_camf(&section[..section.len() - 40]).is_err());
929        assert!(decode_camf(&camf_section(5, [u32::MAX, 0, 0, 0], &data)).is_err());
930        assert!(decode_camf(&camf_section(7, [0; 4], &data)).is_err());
931        assert!(CamfStream::new(&section[..20]).is_err());
932    }
933
934    #[test]
935    fn camf_type4_packed_samples() {
936        // 12-bit samples with the TRUE 2x2 prediction, packed two per three bytes.
937        let (cols, rows, seed) = (6usize, 4usize, 2048i32);
938        let vals: Vec<i32> = (0..cols * rows).map(|i| 2048 + ((i * 13) % 29) as i32 - 14).collect();
939        let mut w = W::new();
940        let mut row_start = [[seed; 2]; 2];
941        for r in 0..rows {
942            let mut acc = [0i32; 2];
943            for c in 0..cols {
944                let v = vals[r * cols + c];
945                let p = if c < 2 { row_start[r & 1][c & 1] } else { acc[c & 1] };
946                encode_diff(&mut w, v - p);
947                acc[c & 1] = v;
948                if c < 2 {
949                    row_start[r & 1][c & 1] = v;
950                }
951            }
952        }
953        let mut packed = Vec::new();
954        for pair in vals.chunks(2) {
955            packed.push((pair[0] >> 4) as u8);
956            packed.push(((pair[0] << 4) as u8 & 0xf0) | ((pair[1] >> 8) as u8 & 0x0f));
957            packed.push(pair[1] as u8);
958        }
959        let mut data = camf_table();
960        data.extend_from_slice(&w.finish());
961        // Cut to an odd size: the last byte holds half a sample.
962        let size = packed.len() - 1;
963        let section = camf_section(4, [size as u32, seed as u32, cols as u32, rows as u32], &data);
964        assert_eq!(decode_camf(&section).unwrap(), &packed[..size]);
965        let mut s = CamfStream::new(&section).unwrap();
966        s.fill(7).unwrap();
967        s.fill(20).unwrap();
968        s.fill(usize::MAX).unwrap();
969        assert_eq!(s.decoded(), &packed[..size]);
970        // A declared size beyond the samples leaves zeros.
971        let section = camf_section(4, [packed.len() as u32 + 5, seed as u32, cols as u32, rows as u32], &data);
972        let out = decode_camf(&section).unwrap();
973        assert_eq!((&out[..packed.len()], &out[packed.len()..]), (&packed[..], &[0u8; 5][..]));
974    }
975}