Skip to main content

oximedia_bitstream/read/
bit_reader.rs

1// Copyright 2017 Brian Langenberger
2// Copyright 2024-2026 COOLJAPAN OU (Team Kitasan)
3//
4// Licensed under the Apache License, Version 2.0 or the MIT license,
5// at your option. See the LICENSE-APACHE / LICENSE-MIT files for details.
6
7//! The concrete `BitReader` type.
8
9use core::convert::TryInto;
10use std::io;
11
12use super::{
13    skip_aligned, BitCount, BitRead, ByteReader, Endianness, PhantomData, Primitive,
14    SignedBitCount, SignedInteger, UnsignedInteger,
15};
16
17/// For reading non-aligned bits from a stream of bytes in a given endianness.
18///
19/// This will read exactly as many whole bytes needed to return
20/// the requested number of bits.  It may cache up to a single partial byte
21/// but no more.
22#[derive(Clone, Debug)]
23pub struct BitReader<R, E: Endianness> {
24    // our underlying reader
25    reader: R,
26    // our partial byte
27    value: u8,
28    // the number of bits in our partial byte
29    bits: u32,
30    // a container for our endiannness
31    phantom: PhantomData<E>,
32}
33
34impl<R, E: Endianness> BitReader<R, E> {
35    /// Wraps a BitReader around something that implements `Read`
36    pub fn new(reader: R) -> BitReader<R, E> {
37        BitReader {
38            reader,
39            value: 0,
40            bits: 0,
41            phantom: PhantomData,
42        }
43    }
44
45    /// Wraps a BitReader around something that implements `Read`
46    /// with the given endianness.
47    pub fn endian(reader: R, _endian: E) -> BitReader<R, E> {
48        BitReader {
49            reader,
50            value: 0,
51            bits: 0,
52            phantom: PhantomData,
53        }
54    }
55
56    /// Unwraps internal reader and disposes of BitReader.
57    ///
58    /// # Warning
59    ///
60    /// Any unread partial bits are discarded.
61    #[inline]
62    pub fn into_reader(self) -> R {
63        self.reader
64    }
65}
66
67impl<R: io::Read, E: Endianness> BitReader<R, E> {
68    /// If stream is byte-aligned, provides mutable reference
69    /// to internal reader.  Otherwise returns `None`
70    #[inline]
71    pub fn reader(&mut self) -> Option<&mut R> {
72        if BitRead::byte_aligned(self) {
73            Some(&mut self.reader)
74        } else {
75            None
76        }
77    }
78
79    /// Returns byte-aligned mutable reference to internal reader.
80    ///
81    /// Bytes aligns stream if it is not already aligned.
82    #[inline]
83    pub fn aligned_reader(&mut self) -> &mut R {
84        BitRead::byte_align(self);
85        &mut self.reader
86    }
87
88    /// Converts `BitReader` to `ByteReader` in the same endianness.
89    ///
90    /// # Warning
91    ///
92    /// Any unread partial bits are discarded.
93    #[inline]
94    pub fn into_bytereader(self) -> ByteReader<R, E> {
95        ByteReader::new(self.into_reader())
96    }
97
98    /// If stream is byte-aligned, provides temporary `ByteReader`
99    /// in the same endianness.  Otherwise returns `None`
100    ///
101    /// # Warning
102    ///
103    /// Any reader bits left over when `ByteReader` is dropped are lost.
104    #[inline]
105    pub fn bytereader(&mut self) -> Option<ByteReader<&mut R, E>> {
106        self.reader().map(ByteReader::new)
107    }
108}
109
110impl<R: io::Read, E: Endianness> BitRead for BitReader<R, E> {
111    #[inline(always)]
112    fn read_bit(&mut self) -> io::Result<bool> {
113        let Self {
114            value,
115            bits,
116            reader,
117            ..
118        } = self;
119        E::pop_bit_refill(reader, value, bits)
120    }
121
122    #[inline(always)]
123    fn read_unsigned_counted<const BITS: u32, U>(&mut self, bits: BitCount<BITS>) -> io::Result<U>
124    where
125        U: UnsignedInteger,
126    {
127        let Self {
128            value: queue_value,
129            bits: queue_bits,
130            reader,
131            ..
132        } = self;
133        E::read_bits(reader, queue_value, queue_bits, bits)
134    }
135
136    #[inline]
137    fn read_unsigned<const BITS: u32, U>(&mut self) -> io::Result<U>
138    where
139        U: UnsignedInteger,
140    {
141        let Self {
142            value,
143            bits,
144            reader,
145            ..
146        } = self;
147        E::read_bits_fixed::<BITS, R, U>(reader, value, bits)
148    }
149
150    #[inline(always)]
151    fn read_signed_counted<const MAX: u32, S>(
152        &mut self,
153        bits: impl TryInto<SignedBitCount<MAX>>,
154    ) -> io::Result<S>
155    where
156        S: SignedInteger,
157    {
158        E::read_signed_counted(
159            self,
160            bits.try_into().map_err(|_| {
161                io::Error::new(
162                    io::ErrorKind::InvalidInput,
163                    "signed reads need at least 1 bit for sign",
164                )
165            })?,
166        )
167    }
168
169    #[inline]
170    fn read_signed<const BITS: u32, S>(&mut self) -> io::Result<S>
171    where
172        S: SignedInteger,
173    {
174        let count = const {
175            assert!(BITS <= S::BITS_SIZE, "excessive bits for type read");
176            let count = BitCount::<BITS>::new::<BITS>().signed_count();
177            match count {
178                Some(c) => c,
179                None => panic!("signed reads need at least 1 bit for sign"),
180            }
181        };
182
183        E::read_signed_counted(self, count)
184    }
185
186    #[inline]
187    fn read_to<V>(&mut self) -> io::Result<V>
188    where
189        V: Primitive,
190    {
191        let mut buffer = V::buffer();
192        E::read_bytes::<8, _>(
193            &mut self.reader,
194            &mut self.value,
195            self.bits,
196            buffer.as_mut(),
197        )?;
198        Ok(E::bytes_to_primitive(buffer))
199    }
200
201    #[inline]
202    fn read_as_to<F, V>(&mut self) -> io::Result<V>
203    where
204        F: Endianness,
205        V: Primitive,
206    {
207        let mut buffer = V::buffer();
208        F::read_bytes::<8, _>(
209            &mut self.reader,
210            &mut self.value,
211            self.bits,
212            buffer.as_mut(),
213        )?;
214        Ok(F::bytes_to_primitive(buffer))
215    }
216
217    /// # Examples
218    /// ```
219    /// use std::io::Read;
220    /// use oximedia_bitstream::{BigEndian, BitReader, BitRead};
221    /// let data = [0b10110111];
222    /// let mut reader = BitReader::endian(data.as_slice(), BigEndian);
223    /// assert!(reader.skip(3).is_ok());
224    /// assert_eq!(reader.read::<5, u8>().unwrap(), 0b10111);
225    /// ```
226    ///
227    /// ```
228    /// use std::io::Read;
229    /// use oximedia_bitstream::{LittleEndian, BitReader, BitRead};
230    /// let data = [0b10110111];
231    /// let mut reader = BitReader::endian(data.as_slice(), LittleEndian);
232    /// assert!(reader.skip(3).is_ok());
233    /// assert_eq!(reader.read::<5, u8>().unwrap(), 0b10110);
234    /// ```
235    fn skip(&mut self, mut bits: u32) -> io::Result<()> {
236        if BitRead::byte_aligned(self) && bits % 8 == 0 {
237            skip_aligned(self.reader.by_ref(), bits / 8)
238        } else {
239            loop {
240                match bits {
241                    0 => break Ok(()),
242                    bits @ 1..64 => break self.read_var(bits).map(|_: u64| ()),
243                    _ => {
244                        let _ = BitRead::read::<64, u64>(self)?;
245                        bits -= 64;
246                    }
247                }
248            }
249        }
250    }
251
252    /// # Example
253    /// ```
254    /// use std::io::Read;
255    /// use oximedia_bitstream::{BigEndian, BitReader, BitRead};
256    /// let data = b"foobar";
257    /// let mut reader = BitReader::endian(data.as_slice(), BigEndian);
258    /// assert!(reader.skip(24).is_ok());
259    /// let mut buf = [0;3];
260    /// assert!(reader.read_bytes(&mut buf).is_ok());
261    /// assert_eq!(&buf, b"bar");
262    /// ```
263    #[inline]
264    fn read_bytes(&mut self, buf: &mut [u8]) -> io::Result<()> {
265        E::read_bytes::<1024, _>(&mut self.reader, &mut self.value, self.bits, buf)
266    }
267
268    fn read_unary<const STOP_BIT: u8>(&mut self) -> io::Result<u32> {
269        let Self {
270            value,
271            bits,
272            reader,
273            ..
274        } = self;
275        E::pop_unary::<STOP_BIT, R>(reader, value, bits)
276    }
277
278    #[inline]
279    fn byte_aligned(&self) -> bool {
280        self.bits == 0
281    }
282
283    #[inline]
284    fn byte_align(&mut self) {
285        self.value = 0;
286        self.bits = 0;
287    }
288}
289
290impl<R, E> BitReader<R, E>
291where
292    E: Endianness,
293    R: io::Read + io::Seek,
294{
295    /// # Example
296    /// ```
297    /// use std::io::{Read, Cursor, SeekFrom};
298    /// use oximedia_bitstream::{BigEndian, BitReader, BitRead};
299    /// let data = [0x00, 0xFF];
300    /// let mut reader = BitReader::endian(Cursor::new(&data), BigEndian);
301    /// assert_eq!(reader.position_in_bits().unwrap(), 0);
302    ///
303    /// let pos = reader.seek_bits(SeekFrom::Start(5)).unwrap();
304    /// assert!(pos == 5 && 5 == reader.position_in_bits().unwrap());
305    ///
306    /// let pos = reader.seek_bits(SeekFrom::Current(-2)).unwrap();
307    /// assert!(pos == 3 && 3 == reader.position_in_bits().unwrap());
308    ///
309    /// let pos = reader.seek_bits(SeekFrom::End(5)).unwrap();
310    /// assert!(pos == 11 && 11 == reader.position_in_bits().unwrap());
311    /// ```
312    pub fn seek_bits(&mut self, from: io::SeekFrom) -> io::Result<u64> {
313        match from {
314            io::SeekFrom::Start(from_start_pos) => {
315                let (bytes, bits) = (from_start_pos / 8, (from_start_pos % 8) as u32);
316                BitRead::byte_align(self);
317                self.reader.seek(io::SeekFrom::Start(bytes))?;
318                BitRead::skip(self, bits)?;
319                Ok(from_start_pos)
320            }
321            io::SeekFrom::End(from_end_pos) => {
322                let reader_end = self.reader.seek(io::SeekFrom::End(0))?;
323                let new_pos = (reader_end * 8) as i64 - from_end_pos;
324                assert!(new_pos >= 0, "The final position should be greater than 0");
325                self.seek_bits(io::SeekFrom::Start(new_pos as u64))
326            }
327            io::SeekFrom::Current(offset) => {
328                let new_pos = self.position_in_bits()? as i64 + offset;
329                assert!(new_pos >= 0, "The final position should be greater than 0");
330                self.seek_bits(io::SeekFrom::Start(new_pos as u64))
331            }
332        }
333    }
334
335    /// # Example
336    /// ```
337    /// use std::fs::read;
338    /// use std::io::{Read, Cursor, SeekFrom};
339    /// use oximedia_bitstream::{BigEndian, BitReader, BitRead};
340    /// let data = [0x00, 0xFF];
341    /// let mut reader = BitReader::endian(Cursor::new(&data), BigEndian);
342    /// assert_eq!(reader.position_in_bits().unwrap(), 0);
343    ///
344    /// let _: i32 = reader.read_signed::<5, _>().unwrap();
345    /// assert_eq!(reader.position_in_bits().unwrap(), 5);
346    ///
347    /// reader.read_bit().unwrap();
348    /// assert_eq!(reader.position_in_bits().unwrap(), 6);
349    /// ```
350    #[inline]
351    #[allow(clippy::seek_from_current)]
352    pub fn position_in_bits(&mut self) -> io::Result<u64> {
353        // core2 doesn't have `seek_from_current`
354        let bytes = self.reader.seek(io::SeekFrom::Current(0))?;
355        Ok(bytes * 8 - (self.bits as u64))
356    }
357}