Skip to main content

revelo_util/
bitstream.rs

1//! Transliteration of `ZenLib::BitStream` — MSB-first bit reader.
2//!
3//! Behavior matches the C++ header line-for-line: same field set, same
4//! underrun semantics (read past end zeros remaining state and returns 0),
5//! same bookmark/peek mechanics, same Byte_Align that consumes the partial
6//! byte. The C++ holds a `const Int8u*` that gets advanced; here we keep
7//! the slice and track an offset index — equivalent state, no `unsafe`.
8
9use crate::types::{Int8u, Int16u, Int32u, Int64u};
10
11const MASK: [u32; 33] = [
12    0x0000_0000,
13    0x0000_0001,
14    0x0000_0003,
15    0x0000_0007,
16    0x0000_000f,
17    0x0000_001f,
18    0x0000_003f,
19    0x0000_007f,
20    0x0000_00ff,
21    0x0000_01ff,
22    0x0000_03ff,
23    0x0000_07ff,
24    0x0000_0fff,
25    0x0000_1fff,
26    0x0000_3fff,
27    0x0000_7fff,
28    0x0000_ffff,
29    0x0001_ffff,
30    0x0003_ffff,
31    0x0007_ffff,
32    0x000f_ffff,
33    0x001f_ffff,
34    0x003f_ffff,
35    0x007f_ffff,
36    0x00ff_ffff,
37    0x01ff_ffff,
38    0x03ff_ffff,
39    0x07ff_ffff,
40    0x0fff_ffff,
41    0x1fff_ffff,
42    0x3fff_ffff,
43    0x7fff_ffff,
44    0xffff_ffff,
45];
46
47#[derive(Clone, Copy)]
48struct Snapshot {
49    pos: usize,
50    buffer_size: usize,
51    last_byte: usize,
52    last_byte_size: usize,
53    buffer_under_run: bool,
54}
55
56pub struct BitStream<'a> {
57    buffer: &'a [u8],
58    pos: usize,
59    buffer_size: usize,
60    buffer_size_init: usize,
61    buffer_size_before_last_call: usize,
62    last_byte: usize,
63    last_byte_size: usize,
64    buffer_under_run: bool,
65    bookmark: Option<Snapshot>,
66}
67
68impl<'a> BitStream<'a> {
69    pub fn new(buffer: &'a [u8]) -> Self {
70        let bits = buffer.len() * 8;
71        BitStream {
72            buffer,
73            pos: 0,
74            buffer_size: bits,
75            buffer_size_init: bits,
76            buffer_size_before_last_call: bits,
77            last_byte: 0,
78            last_byte_size: 0,
79            buffer_under_run: buffer.is_empty(),
80            bookmark: None,
81        }
82    }
83
84    pub fn attach(&mut self, buffer: &'a [u8]) {
85        if std::ptr::eq(buffer.as_ptr(), self.buffer.as_ptr()) && buffer.len() == self.buffer.len()
86        {
87            return;
88        }
89        let bits = buffer.len() * 8;
90        self.buffer = buffer;
91        self.pos = 0;
92        self.buffer_size = bits;
93        self.buffer_size_init = bits;
94        self.buffer_size_before_last_call = bits;
95        self.last_byte_size = 0;
96        self.buffer_under_run = buffer.is_empty();
97        self.bookmark = None;
98    }
99
100    pub fn get(&mut self, how_many: usize) -> Int32u {
101        let to_return: usize;
102        if how_many == 0 || how_many > 32 {
103            return 0;
104        }
105        if how_many > self.buffer_size + self.last_byte_size {
106            self.buffer_size = 0;
107            self.last_byte_size = 0;
108            self.buffer_under_run = true;
109            return 0;
110        }
111
112        self.buffer_size_before_last_call = self.buffer_size + self.last_byte_size;
113
114        if how_many <= self.last_byte_size {
115            self.last_byte_size -= how_many;
116            to_return = self.last_byte >> self.last_byte_size;
117        } else {
118            let mut new_bits = how_many - self.last_byte_size;
119            let mut acc: usize = if new_bits == 32 { 0 } else { self.last_byte << new_bits };
120            // Mirror the C++ switch/fallthrough: pull whole bytes until <=8
121            // bits remain to consume.
122            let mut tier = (new_bits - 1) / 8;
123            while tier >= 1 {
124                new_bits -= 8;
125                acc |= (self.buffer[self.pos] as usize) << new_bits;
126                self.pos += 1;
127                self.buffer_size -= 8;
128                tier -= 1;
129            }
130            // case 0: load the next byte as the new LastByte
131            self.last_byte = self.buffer[self.pos] as usize;
132            self.pos += 1;
133            self.last_byte_size = self.buffer_size.min(8) - new_bits;
134            self.buffer_size -= self.buffer_size.min(8);
135            acc |= (self.last_byte >> self.last_byte_size) & MASK[new_bits] as usize;
136            to_return = acc;
137        }
138        (to_return as u32) & MASK[how_many]
139    }
140
141    pub fn getb(&mut self) -> bool {
142        self.get(1) != 0
143    }
144
145    pub fn get1(&mut self, how_many: usize) -> Int8u {
146        self.get(how_many) as Int8u
147    }
148
149    pub fn get2(&mut self, how_many: usize) -> Int16u {
150        self.get(how_many) as Int16u
151    }
152
153    pub fn get4(&mut self, how_many: usize) -> Int32u {
154        self.get(how_many)
155    }
156
157    pub fn get8(&mut self, how_many: usize) -> Int64u {
158        if how_many > 64 {
159            return 0;
160        }
161        let how_many1 = how_many.saturating_sub(32);
162        let how_many2 = how_many - how_many1;
163        let value1 = self.get(how_many1) as Int64u;
164        let value2 = self.get(how_many2) as Int64u;
165        if self.buffer_under_run {
166            return 0;
167        }
168        value1 * 0x1_0000_0000 + value2
169    }
170
171    pub fn skip(&mut self, mut how_many: usize) {
172        if how_many == 0 {
173            return;
174        }
175        if how_many > 32 {
176            while how_many > 32 {
177                self.skip(32);
178                how_many -= 32;
179            }
180            if how_many > 0 {
181                self.skip(how_many);
182            }
183            return;
184        }
185        if how_many > self.buffer_size + self.last_byte_size {
186            self.buffer_size = 0;
187            self.last_byte_size = 0;
188            self.buffer_under_run = true;
189            return;
190        }
191        self.buffer_size_before_last_call = self.buffer_size + self.last_byte_size;
192
193        if how_many <= self.last_byte_size {
194            self.last_byte_size -= how_many;
195        } else {
196            let mut new_bits = how_many - self.last_byte_size;
197            let mut tier = (new_bits - 1) / 8;
198            while tier >= 1 {
199                new_bits -= 8;
200                self.pos += 1;
201                self.buffer_size -= 8;
202                tier -= 1;
203            }
204            self.last_byte = self.buffer[self.pos] as usize;
205            self.pos += 1;
206            self.last_byte_size = self.buffer_size.min(8) - new_bits;
207            self.buffer_size -= self.buffer_size.min(8);
208        }
209    }
210
211    pub fn skipb(&mut self) {
212        self.skip(1)
213    }
214    pub fn skip1(&mut self, how_many: usize) {
215        self.skip(how_many)
216    }
217    pub fn skip2(&mut self, how_many: usize) {
218        self.skip(how_many)
219    }
220    pub fn skip4(&mut self, how_many: usize) {
221        self.skip(how_many)
222    }
223
224    pub fn skip8(&mut self, how_many: usize) {
225        if how_many > 64 {
226            return;
227        }
228        let how_many1 = how_many.saturating_sub(32);
229        let how_many2 = how_many - how_many1;
230        self.skip(how_many1);
231        self.skip(how_many2);
232    }
233
234    pub fn peek(&mut self, how_many: usize) -> Int32u {
235        self.bookmark_pos(true);
236        let v = self.get(how_many);
237        self.bookmark_pos(false);
238        v
239    }
240
241    pub fn peekb(&mut self) -> bool {
242        self.peek(1) != 0
243    }
244    pub fn peek1(&mut self, how_many: usize) -> Int8u {
245        self.peek(how_many) as Int8u
246    }
247    pub fn peek2(&mut self, how_many: usize) -> Int16u {
248        self.peek(how_many) as Int16u
249    }
250    pub fn peek3(&mut self, how_many: usize) -> Int32u {
251        self.peek(how_many)
252    }
253    pub fn peek4(&mut self, how_many: usize) -> Int32u {
254        self.peek(how_many)
255    }
256    pub fn peek8(&mut self, how_many: usize) -> Int64u {
257        self.peek(how_many) as Int64u
258    }
259
260    pub fn bookmark_pos(&mut self, set: bool) {
261        if set {
262            self.bookmark = Some(Snapshot {
263                pos: self.pos,
264                buffer_size: self.buffer_size,
265                last_byte: self.last_byte,
266                last_byte_size: self.last_byte_size,
267                buffer_under_run: self.buffer_under_run,
268            });
269        } else if let Some(s) = self.bookmark.take() {
270            self.pos = s.pos;
271            self.buffer_size = s.buffer_size;
272            self.last_byte = s.last_byte;
273            self.last_byte_size = s.last_byte_size;
274            self.buffer_under_run = s.buffer_under_run;
275        }
276    }
277
278    pub fn remain(&self) -> Int32u {
279        (self.buffer_size + self.last_byte_size) as Int32u
280    }
281
282    pub fn byte_align(&mut self) {
283        self.get(self.last_byte_size);
284    }
285
286    pub fn offset_get(&self) -> usize {
287        if self.buffer_under_run {
288            return 0;
289        }
290        (self.buffer_size_init - self.buffer_size) / 8
291    }
292
293    pub fn bit_offset_get(&self) -> usize {
294        if self.buffer_under_run {
295            return 0;
296        }
297        self.last_byte_size
298    }
299
300    pub fn offset_before_last_call_get(&self) -> usize {
301        if self.buffer_under_run {
302            return 0;
303        }
304        (self.buffer_size_init - self.buffer_size_before_last_call) / 8
305    }
306
307    pub fn buffer_under_run(&self) -> bool {
308        self.buffer_under_run
309    }
310}
311
312#[cfg(test)]
313mod tests {
314    use super::*;
315
316    #[test]
317    fn read_single_bits_msb_first() {
318        // 0b1010_1100 = 0xAC
319        let mut bs = BitStream::new(&[0xAC]);
320        assert!(bs.getb());
321        assert!(!bs.getb());
322        assert!(bs.getb());
323        assert!(!bs.getb());
324        assert!(bs.getb());
325        assert!(bs.getb());
326        assert!(!bs.getb());
327        assert!(!bs.getb());
328    }
329
330    #[test]
331    fn read_nibbles_across_bytes() {
332        let mut bs = BitStream::new(&[0xAB, 0xCD, 0xEF]);
333        assert_eq!(bs.get(4), 0xA);
334        assert_eq!(bs.get(4), 0xB);
335        assert_eq!(bs.get(4), 0xC);
336        assert_eq!(bs.get(4), 0xD);
337        assert_eq!(bs.get(4), 0xE);
338        assert_eq!(bs.get(4), 0xF);
339        assert!(!bs.buffer_under_run());
340    }
341
342    #[test]
343    fn read_32_bits_aligned() {
344        let mut bs = BitStream::new(&[0xDE, 0xAD, 0xBE, 0xEF]);
345        assert_eq!(bs.get(32), 0xDEAD_BEEF);
346    }
347
348    #[test]
349    fn read_64_bits_via_get8() {
350        let mut bs = BitStream::new(&[0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE]);
351        assert_eq!(bs.get8(64), 0xDEAD_BEEF_CAFE_BABE);
352    }
353
354    #[test]
355    fn read_unaligned_3_bits_then_5() {
356        // 0b1101_1010 = 0xDA — first 3 = 110 (6), next 5 = 11010 (26)
357        let mut bs = BitStream::new(&[0xDA]);
358        assert_eq!(bs.get(3), 6);
359        assert_eq!(bs.get(5), 26);
360    }
361
362    #[test]
363    fn underrun_zeros_result_and_flags() {
364        let mut bs = BitStream::new(&[0xFF]);
365        assert_eq!(bs.get(16), 0);
366        assert!(bs.buffer_under_run());
367        assert_eq!(bs.remain(), 0);
368    }
369
370    #[test]
371    fn peek_does_not_advance() {
372        let mut bs = BitStream::new(&[0xAB, 0xCD]);
373        assert_eq!(bs.peek(8), 0xAB);
374        assert_eq!(bs.peek(8), 0xAB);
375        assert_eq!(bs.get(8), 0xAB);
376        assert_eq!(bs.get(8), 0xCD);
377    }
378
379    #[test]
380    fn skip_then_read() {
381        let mut bs = BitStream::new(&[0xAB, 0xCD, 0xEF]);
382        bs.skip(12);
383        assert_eq!(bs.get(12), 0xDEF);
384    }
385
386    #[test]
387    fn skip_more_than_32() {
388        let mut bs = BitStream::new(&[0; 8]);
389        bs.skip(40);
390        assert_eq!(bs.remain(), 24);
391    }
392
393    #[test]
394    fn byte_align_consumes_partial_byte() {
395        let mut bs = BitStream::new(&[0xAB, 0xCD]);
396        assert_eq!(bs.get(3), 0b101);
397        assert_eq!(bs.bit_offset_get(), 5);
398        bs.byte_align();
399        assert_eq!(bs.bit_offset_get(), 0);
400        assert_eq!(bs.get(8), 0xCD);
401    }
402
403    #[test]
404    fn offset_tracking() {
405        let mut bs = BitStream::new(&[0x00, 0x00, 0x00, 0x00]);
406        assert_eq!(bs.offset_get(), 0);
407        bs.get(16);
408        assert_eq!(bs.offset_get(), 2);
409    }
410}