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}