Skip to main content

flashraw_core/
bits.rs

1//! High-throughput bit readers ("bit pumps").
2//!
3//! RAW codecs consume bit streams in several orders:
4//!
5//! | Pump        | Bit order inside a word                    | Used by (examples)                         |
6//! |-------------|--------------------------------------------|--------------------------------------------|
7//! | [`BitPumpMsb`]   | MSB-first, bytes in order              | Nikon, Pentax, Canon CRW/CRX, packed BE    |
8//! | [`BitPumpJpeg`]  | MSB-first with `FF 00` unstuffing      | lossless JPEG (CR2, DNG, Sony, Kodak...)  |
9//! | [`BitPumpLsb`]   | LSB-first, bytes in order              | Panasonic, Olympus? (no), packed LE        |
10//! | [`BitPumpMsb16`] | MSB-first inside 16-bit LE words       | Sony/Olympus packed variants, Fuji        |
11//! | [`BitPumpMsb32`] | MSB-first inside 32-bit LE words       | Samsung, Phase One, Hasselblad packed      |
12//!
13//! All pumps keep a 64-bit cache. The hot refill reads 8 bytes at once and tops the
14//! cache up to at least 56 valid bits without per-byte branches; the last few bytes
15//! of a stream go through a bounds-checked slow path that pads with zeros. Reading
16//! past the end never panics: it yields zero bits and increments an overrun counter
17//! that decoders check (see [`BitRead::overrun`]) to reject truncated/corrupt data
18//! instead of looping forever.
19
20/// Common interface of all bit pumps.
21pub trait BitRead {
22    /// Ensure at least 32 bits are buffered (zero-padded past the end of input).
23    fn fill(&mut self);
24    /// Peek `n <= 32` bits. Requires a prior [`BitRead::fill`].
25    fn peek_no_fill(&self, n: u32) -> u32;
26    /// Discard `n <= 32` bits. Requires that `n` bits are buffered.
27    fn skip_no_fill(&mut self, n: u32);
28    /// Number of bytes consumed from the input (bits not yet used are excluded).
29    fn byte_position(&self) -> usize;
30    /// Bytes requested past the end of the input (0 for a well-formed stream). Includes
31    /// look-ahead that has not been consumed; see [`BitRead::past_end`].
32    fn overrun(&self) -> usize;
33    /// Bits currently buffered (not yet consumed).
34    fn buffered(&self) -> u32;
35
36    /// Bytes *consumed* beyond the end of the input (padding fed but still buffered is
37    /// not counted). Decoders use this to detect truncated streams precisely.
38    #[inline]
39    fn past_end(&self) -> usize {
40        self.overrun().saturating_sub(self.buffered() as usize / 8)
41    }
42
43    /// Ensure at least `n` bits (`n <= 56`) are buffered (zero padding past the end).
44    #[inline(always)]
45    fn fill_to(&mut self, n: u32) {
46        if self.buffered() < n {
47            self.refill_force();
48        }
49    }
50    /// Refill to the pump's maximum fill level even if 32 or more bits are buffered.
51    fn refill_force(&mut self);
52
53    #[inline(always)]
54    fn peek(&mut self, n: u32) -> u32 {
55        self.fill();
56        self.peek_no_fill(n)
57    }
58    #[inline(always)]
59    fn get(&mut self, n: u32) -> u32 {
60        self.fill();
61        let v = self.peek_no_fill(n);
62        self.skip_no_fill(n);
63        v
64    }
65    #[inline(always)]
66    fn skip(&mut self, mut n: u32) {
67        while n > 32 {
68            self.fill();
69            self.skip_no_fill(32);
70            n -= 32;
71        }
72        self.fill();
73        self.skip_no_fill(n);
74    }
75    /// Read a single bit.
76    #[inline(always)]
77    fn bit(&mut self) -> u32 {
78        self.get(1)
79    }
80    /// True if the stream ran (meaningfully) past the end of its data.
81    #[inline]
82    fn exhausted(&self) -> bool {
83        // Up to 8 bytes of padding are normal look-ahead; anything beyond means
84        // the decoder consumed bits that do not exist.
85        self.overrun() > 8
86    }
87}
88
89#[inline(always)]
90fn mask(n: u32) -> u64 {
91    (1u64 << n) - 1
92}
93
94macro_rules! common_fields {
95    () => {
96        /// Create a pump over `data`.
97        pub fn new(data: &'a [u8]) -> Self {
98            Self { data, pos: 0, cache: 0, bits: 0, overrun: 0 }
99        }
100        /// Remaining unread input (from the byte position of the refill cursor).
101        pub fn data(&self) -> &'a [u8] {
102            self.data
103        }
104        /// Bits currently buffered.
105        #[inline(always)]
106        pub fn buffered_bits(&self) -> u32 {
107            self.bits
108        }
109    };
110}
111
112/// MSB-first bit pump (big-endian bit order).
113#[derive(Clone, Copy)]
114pub struct BitPumpMsb<'a> {
115    data: &'a [u8],
116    pos: usize,
117    /// Valid bits are left-aligned (bit 63 is the next bit).
118    cache: u64,
119    bits: u32,
120    overrun: usize,
121}
122
123impl<'a> BitPumpMsb<'a> {
124    common_fields!();
125
126    /// The end-of-input refill. Takes and returns the pump by value so a pump held in
127    /// a local stays in registers in hot loops (a `&mut self` call would pin it to memory).
128    #[cold]
129    #[inline(never)]
130    fn filled_slow(mut self) -> Self {
131        self.fill_slow();
132        self
133    }
134
135    fn fill_slow(&mut self) {
136        while self.bits <= 56 {
137            let b = match self.data.get(self.pos) {
138                Some(&b) => b,
139                None => {
140                    self.overrun += 1;
141                    0
142                }
143            };
144            self.pos += 1;
145            self.cache |= (b as u64) << (56 - self.bits);
146            self.bits += 8;
147        }
148    }
149
150    /// Discard bits up to the next byte boundary.
151    pub fn align_byte(&mut self) {
152        let r = self.bits % 8;
153        self.skip_no_fill(r);
154    }
155
156    /// Bits consumed from the start of the input (padding past the end included).
157    #[inline(always)]
158    pub fn bit_position(&self) -> u64 {
159        self.pos as u64 * 8 - self.bits as u64
160    }
161
162    /// A pump positioned `bit` bits into `data`.
163    pub fn at_bit(data: &'a [u8], bit: u64) -> Self {
164        let mut p = Self::new(data.get((bit / 8) as usize..).unwrap_or(&[]));
165        p.fill();
166        p.skip_no_fill((bit % 8) as u32);
167        p.pos += (bit / 8) as usize;
168        p.data = data;
169        p
170    }
171}
172
173impl BitRead for BitPumpMsb<'_> {
174    #[inline(always)]
175    fn fill(&mut self) {
176        if self.bits >= 32 {
177            return;
178        }
179        self.refill_force();
180    }
181    #[inline(always)]
182    fn refill_force(&mut self) {
183        if let Some(chunk) = self.data.get(self.pos..self.pos + 8) {
184            let w = u64::from_be_bytes(chunk.try_into().unwrap());
185            self.cache |= w >> self.bits;
186            self.pos += ((63 - self.bits) >> 3) as usize;
187            self.bits |= 56;
188        } else {
189            *self = self.filled_slow();
190        }
191    }
192    #[inline(always)]
193    fn peek_no_fill(&self, n: u32) -> u32 {
194        (self.cache.rotate_left(n) & mask(n)) as u32
195    }
196    #[inline(always)]
197    fn skip_no_fill(&mut self, n: u32) {
198        debug_assert!(n <= self.bits);
199        self.cache <<= n;
200        self.bits -= n;
201    }
202    fn byte_position(&self) -> usize {
203        self.pos - (self.bits as usize >> 3)
204    }
205    fn overrun(&self) -> usize {
206        self.overrun
207    }
208    fn buffered(&self) -> u32 {
209        self.bits
210    }
211}
212
213/// LSB-first bit pump (little-endian bit order).
214#[derive(Clone)]
215pub struct BitPumpLsb<'a> {
216    data: &'a [u8],
217    pos: usize,
218    /// Valid bits are right-aligned (bit 0 is the next bit).
219    cache: u64,
220    bits: u32,
221    overrun: usize,
222}
223
224impl<'a> BitPumpLsb<'a> {
225    common_fields!();
226
227    #[cold]
228    fn fill_slow(&mut self) {
229        while self.bits <= 56 {
230            let b = match self.data.get(self.pos) {
231                Some(&b) => b,
232                None => {
233                    self.overrun += 1;
234                    0
235                }
236            };
237            self.pos += 1;
238            self.cache |= (b as u64) << self.bits;
239            self.bits += 8;
240        }
241    }
242}
243
244impl BitRead for BitPumpLsb<'_> {
245    #[inline(always)]
246    fn fill(&mut self) {
247        if self.bits >= 32 {
248            return;
249        }
250        self.refill_force();
251    }
252    #[inline(always)]
253    fn refill_force(&mut self) {
254        if let Some(chunk) = self.data.get(self.pos..self.pos + 8) {
255            let w = u64::from_le_bytes(chunk.try_into().unwrap());
256            self.cache |= w << self.bits;
257            self.pos += ((63 - self.bits) >> 3) as usize;
258            self.bits |= 56;
259        } else {
260            self.fill_slow();
261        }
262    }
263    #[inline(always)]
264    fn peek_no_fill(&self, n: u32) -> u32 {
265        (self.cache & mask(n)) as u32
266    }
267    #[inline(always)]
268    fn skip_no_fill(&mut self, n: u32) {
269        debug_assert!(n <= self.bits);
270        self.cache >>= n;
271        self.bits -= n;
272    }
273    fn byte_position(&self) -> usize {
274        self.pos - (self.bits as usize >> 3)
275    }
276    fn overrun(&self) -> usize {
277        self.overrun
278    }
279    fn buffered(&self) -> u32 {
280        self.bits
281    }
282}
283
284/// MSB-first bit order inside little-endian words of `W` bytes (2 or 4).
285#[derive(Clone)]
286pub struct BitPumpMsbWords<'a, const W: usize> {
287    data: &'a [u8],
288    pos: usize,
289    cache: u64,
290    bits: u32,
291    overrun: usize,
292}
293
294/// MSB-first inside 16-bit little-endian words.
295pub type BitPumpMsb16<'a> = BitPumpMsbWords<'a, 2>;
296/// MSB-first inside 32-bit little-endian words.
297pub type BitPumpMsb32<'a> = BitPumpMsbWords<'a, 4>;
298
299impl<'a, const W: usize> BitPumpMsbWords<'a, W> {
300    common_fields!();
301
302    /// Bits consumed from the start of the input (padding past the end included).
303    #[inline(always)]
304    pub fn bit_position(&self) -> u64 {
305        self.pos as u64 * 8 - self.bits as u64
306    }
307
308    /// A pump positioned `bit` bits into `data` (word-aligned start, then skipped).
309    pub fn at_bit(data: &'a [u8], bit: u64) -> Self {
310        let word_bits = 8 * W as u64;
311        let base = (bit / word_bits) as usize * W;
312        let mut p = Self::new(data.get(base..).unwrap_or(&[]));
313        p.fill();
314        p.skip_no_fill((bit % word_bits) as u32);
315        p.pos += base;
316        p.data = data;
317        p
318    }
319
320    #[cold]
321    fn fill_slow(&mut self) {
322        while self.bits <= 64 - 8 * W as u32 {
323            let mut w: u64 = 0;
324            for i in (0..W).rev() {
325                let b = match self.data.get(self.pos + i) {
326                    Some(&b) => b,
327                    None => {
328                        self.overrun += 1;
329                        0
330                    }
331                };
332                w = (w << 8) | b as u64;
333            }
334            self.pos += W;
335            self.cache |= w << (64 - 8 * W as u32 - self.bits);
336            self.bits += 8 * W as u32;
337        }
338    }
339}
340
341impl<const W: usize> BitRead for BitPumpMsbWords<'_, W> {
342    #[inline(always)]
343    fn fill(&mut self) {
344        if self.bits >= 32 {
345            return;
346        }
347        self.refill_force();
348    }
349    #[inline(always)]
350    fn refill_force(&mut self) {
351        if let Some(chunk) = self.data.get(self.pos..self.pos + 8) {
352            let le = u64::from_le_bytes(chunk.try_into().unwrap());
353            // Reorder so the first word occupies the top bits.
354            let w = if W == 2 {
355                let x = le;
356                ((x & 0xFFFF) << 48) | ((x & 0xFFFF_0000) << 16) | ((x >> 16) & 0xFFFF_0000) | (x >> 48)
357            } else {
358                le.rotate_left(32)
359            };
360            // Take as many whole words as fit (bits < 32 so at least one fits).
361            let words = (64 - self.bits) / (8 * W as u32);
362            let take = words * 8 * W as u32;
363            let part = if take == 64 { w } else { w >> (64 - take) << (64 - take) };
364            self.cache |= part >> self.bits;
365            self.bits += take;
366            self.pos += (take / 8) as usize;
367        } else {
368            self.fill_slow();
369        }
370    }
371    #[inline(always)]
372    fn peek_no_fill(&self, n: u32) -> u32 {
373        (self.cache.rotate_left(n) & mask(n)) as u32
374    }
375    #[inline(always)]
376    fn skip_no_fill(&mut self, n: u32) {
377        debug_assert!(n <= self.bits);
378        self.cache = if n == 64 { 0 } else { self.cache << n };
379        self.bits -= n;
380    }
381    fn byte_position(&self) -> usize {
382        self.pos - (self.bits as usize >> 3)
383    }
384    fn overrun(&self) -> usize {
385        self.overrun
386    }
387    fn buffered(&self) -> u32 {
388        self.bits
389    }
390}
391
392/// MSB-first pump for JPEG entropy-coded segments: removes `FF 00` byte stuffing and
393/// stops (feeding zeros) at a marker (`FF xx`, `xx != 0`).
394#[derive(Clone)]
395pub struct BitPumpJpeg<'a> {
396    data: &'a [u8],
397    pos: usize,
398    cache: u64,
399    bits: u32,
400    overrun: usize,
401    marker_hit: bool,
402}
403
404impl<'a> BitPumpJpeg<'a> {
405    pub fn new(data: &'a [u8]) -> Self {
406        Self { data, pos: 0, cache: 0, bits: 0, overrun: 0, marker_hit: false }
407    }
408    /// Whether a marker terminated the stream.
409    pub fn marker_hit(&self) -> bool {
410        self.marker_hit
411    }
412    /// Byte offset of the read cursor in the source (after unstuffing accounting).
413    pub fn raw_position(&self) -> usize {
414        self.pos
415    }
416
417    #[cold]
418    fn fill_slow(&mut self) {
419        while self.bits <= 56 {
420            let mut b = 0u8;
421            if !self.marker_hit {
422                match self.data.get(self.pos) {
423                    Some(&0xFF) => {
424                        match self.data.get(self.pos + 1) {
425                            Some(&0x00) => {
426                                b = 0xFF;
427                                self.pos += 2;
428                            }
429                            _ => {
430                                // A marker (or EOF after FF): stop consuming input.
431                                self.marker_hit = true;
432                                self.overrun += 1;
433                            }
434                        }
435                    }
436                    Some(&v) => {
437                        b = v;
438                        self.pos += 1;
439                    }
440                    None => {
441                        self.marker_hit = true;
442                        self.overrun += 1;
443                    }
444                }
445            } else {
446                self.overrun += 1;
447            }
448            self.cache |= (b as u64) << (56 - self.bits);
449            self.bits += 8;
450        }
451    }
452
453    /// Reset to the byte position after a restart marker (`FF D0..D7`), if present.
454    pub fn reset_at_restart(&mut self) -> bool {
455        // Discard buffered bits; scan forward to the marker.
456        let mut p = self.byte_position_raw_estimate();
457        while p + 1 < self.data.len() {
458            if self.data[p] == 0xFF && (0xD0..=0xD7).contains(&self.data[p + 1]) {
459                self.pos = p + 2;
460                self.cache = 0;
461                self.bits = 0;
462                self.marker_hit = false;
463                // Zero padding fed while stopped at a restart marker is legitimate,
464                // not an overrun of the segment.
465                self.overrun = 0;
466                return true;
467            }
468            p += 1;
469        }
470        false
471    }
472
473    fn byte_position_raw_estimate(&self) -> usize {
474        // Buffered bytes may include unstuffed FF00 pairs; back up conservatively.
475        self.pos.saturating_sub(((self.bits as usize) >> 3) * 2)
476    }
477}
478
479impl BitRead for BitPumpJpeg<'_> {
480    #[inline(always)]
481    fn fill(&mut self) {
482        if self.bits >= 32 {
483            return;
484        }
485        self.refill_force();
486    }
487    #[inline(always)]
488    fn refill_force(&mut self) {
489        if let Some(chunk) = self.data.get(self.pos..self.pos + 8) {
490            let w = u64::from_be_bytes(chunk.try_into().unwrap());
491            // SWAR test for any 0xFF byte in the word.
492            let inv = !w;
493            let has_ff = (inv.wrapping_sub(0x0101_0101_0101_0101) & !inv & 0x8080_8080_8080_8080) != 0;
494            if !has_ff {
495                self.cache |= w >> self.bits;
496                self.pos += ((63 - self.bits) >> 3) as usize;
497                self.bits |= 56;
498                return;
499            }
500        }
501        self.fill_slow();
502    }
503    #[inline(always)]
504    fn peek_no_fill(&self, n: u32) -> u32 {
505        (self.cache.rotate_left(n) & mask(n)) as u32
506    }
507    #[inline(always)]
508    fn skip_no_fill(&mut self, n: u32) {
509        debug_assert!(n <= self.bits);
510        self.cache <<= n;
511        self.bits -= n;
512    }
513    fn byte_position(&self) -> usize {
514        self.pos.saturating_sub(self.bits as usize >> 3)
515    }
516    fn overrun(&self) -> usize {
517        self.overrun
518    }
519    fn buffered(&self) -> u32 {
520        self.bits
521    }
522}
523
524/// Sign-extend a JPEG-style difference value: `len` bits `v` → signed diff.
525#[inline(always)]
526pub fn extend_diff(v: u32, len: u32) -> i32 {
527    if len == 0 {
528        return 0;
529    }
530    let v = v as i32;
531    if v & (1 << (len - 1)) == 0 { v - (1 << len) + 1 } else { v }
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537
538    fn ref_msb(data: &[u8], widths: &[u32]) -> Vec<u32> {
539        let mut out = vec![];
540        let mut bitpos = 0usize;
541        for &w in widths {
542            let mut v = 0u32;
543            for _ in 0..w {
544                let byte = data.get(bitpos / 8).copied().unwrap_or(0);
545                let bit = (byte >> (7 - bitpos % 8)) & 1;
546                v = (v << 1) | bit as u32;
547                bitpos += 1;
548            }
549            out.push(v);
550        }
551        out
552    }
553    fn ref_lsb(data: &[u8], widths: &[u32]) -> Vec<u32> {
554        let mut out = vec![];
555        let mut bitpos = 0usize;
556        for &w in widths {
557            let mut v = 0u32;
558            for i in 0..w {
559                let byte = data.get(bitpos / 8).copied().unwrap_or(0);
560                let bit = (byte >> (bitpos % 8)) & 1;
561                v |= (bit as u32) << i;
562                bitpos += 1;
563            }
564            out.push(v);
565        }
566        out
567    }
568    fn swap_words(data: &[u8], w: usize) -> Vec<u8> {
569        let mut d = data.to_vec();
570        d.resize(data.len().div_ceil(w) * w, 0);
571        for c in d.chunks_mut(w) {
572            c.reverse();
573        }
574        d
575    }
576
577    fn pseudo(n: usize, seed: u64) -> Vec<u8> {
578        let mut x = seed;
579        (0..n)
580            .map(|_| {
581                x ^= x << 13;
582                x ^= x >> 7;
583                x ^= x << 17;
584                x as u8
585            })
586            .collect()
587    }
588
589    #[test]
590    fn pumps_match_reference() {
591        for seed in 1..20u64 {
592            let data = pseudo(97, seed);
593            let widths: Vec<u32> = (0..120).map(|i| ((i * 7 + seed as usize) % 33) as u32).collect();
594            let mut m = BitPumpMsb::new(&data);
595            let got: Vec<u32> = widths.iter().map(|&w| m.get(w)).collect();
596            assert_eq!(got, ref_msb(&data, &widths), "msb seed {seed}");
597            let mut l = BitPumpLsb::new(&data);
598            let got: Vec<u32> = widths.iter().map(|&w| l.get(w)).collect();
599            assert_eq!(got, ref_lsb(&data, &widths), "lsb seed {seed}");
600            let mut m16 = BitPumpMsb16::new(&data);
601            let got: Vec<u32> = widths.iter().map(|&w| m16.get(w)).collect();
602            assert_eq!(got, ref_msb(&swap_words(&data, 2), &widths), "msb16 seed {seed}");
603            let mut m32 = BitPumpMsb32::new(&data);
604            let got: Vec<u32> = widths.iter().map(|&w| m32.get(w)).collect();
605            assert_eq!(got, ref_msb(&swap_words(&data, 4), &widths), "msb32 seed {seed}");
606        }
607    }
608
609    #[test]
610    fn jpeg_unstuffing() {
611        let data = [0x12, 0xFF, 0x00, 0x34, 0xFF, 0xD9, 0x55];
612        let mut p = BitPumpJpeg::new(&data);
613        assert_eq!(p.get(8), 0x12);
614        assert_eq!(p.get(8), 0xFF);
615        assert_eq!(p.get(8), 0x34);
616        assert_eq!(p.get(8), 0x00); // marker: zeros
617        assert!(p.marker_hit());
618        // long stuffed stream through the fast path
619        let mut d = pseudo(200, 3);
620        for b in d.iter_mut() {
621            if *b == 0xFF {
622                *b = 0xFE;
623            }
624        }
625        let mut stuffed = vec![];
626        for (i, &b) in d.iter().enumerate() {
627            stuffed.push(if i % 17 == 0 { 0xFF } else { b });
628            if i % 17 == 0 {
629                stuffed.push(0);
630            }
631        }
632        let plain: Vec<u8> = d.iter().enumerate().map(|(i, &b)| if i % 17 == 0 { 0xFF } else { b }).collect();
633        let widths: Vec<u32> = (0..300).map(|i| (i % 13) as u32 + 1).collect();
634        let mut p = BitPumpJpeg::new(&stuffed);
635        let got: Vec<u32> = widths.iter().map(|&w| p.get(w)).collect();
636        assert_eq!(got, ref_msb(&plain, &widths));
637    }
638
639    #[test]
640    fn overrun_is_tracked_not_panicking() {
641        let data = [0xAAu8; 3];
642        let mut p = BitPumpMsb::new(&data);
643        for _ in 0..100 {
644            p.get(32);
645        }
646        assert!(p.exhausted());
647        let mut p = BitPumpLsb::new(&[]);
648        assert_eq!(p.get(32), 0);
649        assert!(p.overrun() > 0);
650    }
651
652    #[test]
653    fn diff_extension() {
654        assert_eq!(extend_diff(0, 1), -1);
655        assert_eq!(extend_diff(1, 1), 1);
656        assert_eq!(extend_diff(0b010, 3), -5);
657        assert_eq!(extend_diff(0b110, 3), 6);
658        assert_eq!(extend_diff(0, 0), 0);
659    }
660}