Skip to main content

openjph_core/codestream/
bitbuffer_write.rs

1//! Bit-buffer writer for codestream generation.
2//!
3//! Port of `ojph_bitbuffer_write.h`. Handles JPEG 2000 byte-stuffing:
4//! after writing a 0xFF byte, the next byte must have its MSB clear.
5
6/// Bit-level writer with JPEG 2000 0xFF byte-stuffing.
7#[derive(Debug)]
8pub struct BitBufferWrite {
9    data: Vec<u8>,
10    /// Accumulated bit buffer (left-justified).
11    buf: u64,
12    /// Number of valid bits in `buf`.
13    bits_used: u32,
14    /// True if the last flushed byte was 0xFF.
15    unstuff: bool,
16}
17
18impl BitBufferWrite {
19    /// Create a new bit writer.
20    pub fn new() -> Self {
21        Self {
22            data: Vec::with_capacity(256),
23            buf: 0,
24            bits_used: 0,
25            unstuff: false,
26        }
27    }
28
29    /// Write `n` bits from the MSB side of `val` (n <= 32).
30    #[inline]
31    pub fn write(&mut self, val: u32, n: u32) {
32        debug_assert!(n <= 32);
33        self.buf |= (val as u64) << (64 - self.bits_used - n);
34        self.bits_used += n;
35        if self.bits_used >= 32 {
36            self.flush_bytes();
37        }
38    }
39
40    /// Flush complete bytes from the buffer to the output, applying stuffing.
41    fn flush_bytes(&mut self) {
42        loop {
43            if self.unstuff {
44                if self.bits_used < 7 {
45                    break;
46                }
47                // After 0xFF, output top 7 bits with MSB forced to 0
48                let val = ((self.buf >> 57) as u8) & 0x7F;
49                self.data.push(val);
50                self.buf <<= 7;
51                self.bits_used -= 7;
52                self.unstuff = false;
53            } else {
54                if self.bits_used < 8 {
55                    break;
56                }
57                let byte = (self.buf >> 56) as u8;
58                self.data.push(byte);
59                self.buf <<= 8;
60                self.bits_used -= 8;
61                self.unstuff = byte == 0xFF;
62            }
63        }
64    }
65
66    /// Flush all remaining bits, padding with zeros. Returns whether
67    /// a zero byte was appended after a trailing 0xFF.
68    pub fn finalize(&mut self) -> bool {
69        let mut added_stuffing_zero = false;
70        while self.bits_used > 0 || self.unstuff {
71            if self.bits_used == 0 {
72                // unstuff is true: emit a zero byte after 0xFF
73                self.data.push(0);
74                self.unstuff = false;
75                added_stuffing_zero = true;
76            } else {
77                // Pad remaining bits to the next byte boundary
78                let byte_bits = if self.unstuff { 7u32 } else { 8u32 };
79                if self.bits_used < byte_bits {
80                    self.bits_used = byte_bits;
81                } else {
82                    let rem = self.bits_used % byte_bits;
83                    if rem != 0 {
84                        self.bits_used += byte_bits - rem;
85                    }
86                }
87                self.flush_bytes();
88            }
89        }
90        added_stuffing_zero
91    }
92
93    /// Get the written data.
94    pub fn get_data(&self) -> &[u8] {
95        &self.data
96    }
97
98    /// Take ownership of the written data.
99    pub fn into_data(self) -> Vec<u8> {
100        self.data
101    }
102
103    /// Returns the current byte length of written data.
104    pub fn len(&self) -> usize {
105        self.data.len()
106    }
107
108    /// Returns true if no data has been written.
109    pub fn is_empty(&self) -> bool {
110        self.data.is_empty() && self.bits_used == 0
111    }
112
113    /// Reset the writer.
114    pub fn reset(&mut self) {
115        self.data.clear();
116        self.buf = 0;
117        self.bits_used = 0;
118        self.unstuff = false;
119    }
120}
121
122impl Default for BitBufferWrite {
123    fn default() -> Self {
124        Self::new()
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn empty_writer() {
134        let writer = BitBufferWrite::new();
135        assert!(writer.is_empty());
136        assert_eq!(writer.len(), 0);
137        assert_eq!(writer.get_data(), &[]);
138    }
139
140    #[test]
141    fn write_single_byte() {
142        let mut writer = BitBufferWrite::new();
143        writer.write(0xAB, 8);
144        writer.finalize();
145        assert_eq!(writer.get_data()[0], 0xAB);
146    }
147
148    #[test]
149    fn write_individual_bits() {
150        let mut writer = BitBufferWrite::new();
151        // Write 1,0,1,0,1,0,1,1 = 0xAB
152        writer.write(1, 1);
153        writer.write(0, 1);
154        writer.write(1, 1);
155        writer.write(0, 1);
156        writer.write(1, 1);
157        writer.write(0, 1);
158        writer.write(1, 1);
159        writer.write(1, 1);
160        writer.finalize();
161        assert_eq!(writer.get_data()[0], 0xAB);
162    }
163
164    #[test]
165    fn write_multi_bit_values() {
166        let mut writer = BitBufferWrite::new();
167        writer.write(0xA, 4); // 1010
168        writer.write(0xB, 4); // 1011
169        writer.finalize();
170        assert_eq!(writer.get_data()[0], 0xAB);
171    }
172
173    #[test]
174    fn byte_stuffing_after_0xff() {
175        let mut writer = BitBufferWrite::new();
176        // Write 0xFF (8 bits of 1s)
177        writer.write(0xFF, 8);
178        // After flushing 0xFF, the next byte should have MSB=0
179        // Write 0xFF again → only 7 bits fit in stuffed byte
180        writer.write(0xFF, 8);
181        writer.finalize();
182        let data = writer.get_data();
183        assert_eq!(data[0], 0xFF);
184        // After 0xFF, next byte has MSB forced to 0
185        assert_eq!(data[1] & 0x80, 0x00);
186    }
187
188    #[test]
189    fn finalize_pads_with_zeros() {
190        let mut writer = BitBufferWrite::new();
191        writer.write(0x7, 3); // 111
192        writer.finalize();
193        // 111 padded to 8 bits → 1110_0000 = 0xE0
194        assert_eq!(writer.get_data()[0], 0xE0);
195    }
196
197    #[test]
198    fn finalize_adds_zero_after_final_0xff() {
199        let mut writer = BitBufferWrite::new();
200        writer.write(0xFF, 8);
201        let was_ff = writer.finalize();
202        let data = writer.get_data();
203        // After 0xFF there should be a 0x00 byte appended
204        assert!(data.len() >= 2);
205        assert_eq!(data[0], 0xFF);
206        assert_eq!(data[1], 0x00);
207        // finalize returns true or the trailing zero is present
208        let _ = was_ff;
209    }
210
211    #[test]
212    fn len_and_is_empty() {
213        let mut writer = BitBufferWrite::new();
214        assert!(writer.is_empty());
215        assert_eq!(writer.len(), 0);
216        writer.write(0xAB, 8);
217        writer.write(0xCD, 8);
218        // After writing 16 bits, flush_bytes triggers for both
219        // is_empty now depends on whether bits remain in buffer
220        writer.finalize();
221        assert!(!writer.is_empty());
222        assert!(writer.len() >= 2);
223    }
224
225    #[test]
226    fn reset_clears_all() {
227        let mut writer = BitBufferWrite::new();
228        writer.write(0xAB, 8);
229        writer.write(0xCD, 8);
230        writer.finalize();
231        assert!(!writer.is_empty());
232
233        writer.reset();
234        assert!(writer.is_empty());
235        assert_eq!(writer.len(), 0);
236        assert_eq!(writer.get_data(), &[]);
237    }
238
239    #[test]
240    fn write_then_finalize_small() {
241        let mut writer = BitBufferWrite::new();
242        writer.write(0x5, 3); // 101
243        writer.finalize();
244        // 101_00000 = 0xA0
245        assert_eq!(writer.get_data()[0], 0xA0);
246    }
247
248    #[test]
249    fn write_32_bits() {
250        let mut writer = BitBufferWrite::new();
251        writer.write(0x12345678, 32);
252        writer.finalize();
253        let data = writer.get_data();
254        assert_eq!(data[0], 0x12);
255        assert_eq!(data[1], 0x34);
256        assert_eq!(data[2], 0x56);
257        assert_eq!(data[3], 0x78);
258    }
259
260    #[test]
261    fn into_data_takes_ownership() {
262        let mut writer = BitBufferWrite::new();
263        writer.write(0xAB, 8);
264        writer.finalize();
265        let data = writer.into_data();
266        assert_eq!(data[0], 0xAB);
267    }
268
269    #[test]
270    fn roundtrip_write_then_read() {
271        use super::super::bitbuffer_read::BitBufferRead;
272
273        let mut writer = BitBufferWrite::new();
274        // Write known values of various widths
275        writer.write(0x7, 3); // 111
276        writer.write(0x0, 1); // 0
277        writer.write(0x15, 5); // 10101
278        writer.write(0xAB, 8); // 10101011
279        writer.write(0x3, 2); // 11
280        writer.finalize();
281
282        let data = writer.get_data();
283        let mut reader = BitBufferRead::new(data);
284
285        // Read back in same order
286        assert_eq!(reader.read(3), 0x7);
287        assert_eq!(reader.read(1), 0x0);
288        assert_eq!(reader.read(5), 0x15);
289        assert_eq!(reader.read(8), 0xAB);
290        assert_eq!(reader.read(2), 0x3);
291    }
292
293    #[test]
294    fn roundtrip_with_byte_stuffing() {
295        use super::super::bitbuffer_read::BitBufferRead;
296
297        // Test 1: 0xFF followed by normal data
298        let mut writer = BitBufferWrite::new();
299        writer.write(0xFF, 8);
300        writer.write(0x55, 8);
301        writer.finalize();
302
303        let data = writer.get_data();
304        assert_eq!(data[0], 0xFF);
305        assert_eq!(data[1] & 0x80, 0); // MSB forced to 0 after 0xFF
306
307        let mut reader = BitBufferRead::new(data);
308        assert_eq!(reader.read(8), 0xFF);
309        assert_eq!(reader.read(8), 0x55);
310
311        // Test 2: multiple 0xFF bytes
312        let mut writer = BitBufferWrite::new();
313        writer.write(0xFF, 8);
314        writer.write(0xFF, 8);
315        writer.write(0xAA, 8);
316        writer.finalize();
317
318        let data = writer.get_data();
319        let mut reader = BitBufferRead::new(data);
320        assert_eq!(reader.read(8), 0xFF);
321        assert_eq!(reader.read(8), 0xFF);
322        assert_eq!(reader.read(8), 0xAA);
323
324        // Test 3: 0xFF with mixed bit-width writes
325        let mut writer = BitBufferWrite::new();
326        writer.write(0xFF, 8);
327        writer.write(0x5, 3); // 101
328        writer.write(0xA, 4); // 1010
329        writer.finalize();
330
331        let data = writer.get_data();
332        let mut reader = BitBufferRead::new(data);
333        assert_eq!(reader.read(8), 0xFF);
334        assert_eq!(reader.read(3), 0x5);
335        assert_eq!(reader.read(4), 0xA);
336    }
337
338    #[test]
339    fn default_trait() {
340        let writer = BitBufferWrite::default();
341        assert!(writer.is_empty());
342    }
343}