summaryrefslogtreecommitdiff
path: root/vendor/zune-inflate/src/bitstream.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/zune-inflate/src/bitstream.rs')
-rw-r--r--vendor/zune-inflate/src/bitstream.rs188
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/zune-inflate/src/bitstream.rs b/vendor/zune-inflate/src/bitstream.rs
new file mode 100644
index 0000000..ff55e52
--- /dev/null
+++ b/vendor/zune-inflate/src/bitstream.rs
@@ -0,0 +1,188 @@
+//! `BitStreamReader` API
+//!
+//! This module provides an interface to read and write bits (and bytes) for
+//! huffman
+
+pub struct BitStreamReader<'src>
+{
+ // buffer from which we are pulling in bits from
+ // used in decompression.
+ pub src: &'src [u8],
+ // position in our buffer,
+ pub position: usize,
+ pub bits_left: u8,
+ pub buffer: u64,
+ pub over_read: usize
+}
+
+impl<'src> BitStreamReader<'src>
+{
+ /// Create a new `BitStreamReader` instance
+ ///
+ /// # Expectations
+ /// The buffer must be padded with fill bytes in the end,
+ /// if not, this becomes UB in the refill phase.
+ pub fn new(in_buffer: &'src [u8]) -> BitStreamReader<'src>
+ {
+ BitStreamReader {
+ bits_left: 0,
+ buffer: 0,
+ src: in_buffer,
+ position: 0,
+ over_read: 0
+ }
+ }
+ /// Refill the bitstream ensuring the buffer has bits between
+ /// 56 and 63.
+ ///
+ #[inline(always)]
+ pub fn refill(&mut self)
+ {
+ /*
+ * The refill always guarantees refills between 56-63
+ *
+ * Bits stored will never go above 63 and if bits are in the range 56-63 no refills occur.
+ */
+ let mut buf = [0; 8];
+
+ match self.src.get(self.position..self.position + 8)
+ {
+ Some(bytes) =>
+ {
+ buf.copy_from_slice(bytes);
+ // create a u64 from an array of u8's
+ let new_buffer = u64::from_le_bytes(buf);
+ // num indicates how many bytes we actually consumed.
+ let num = 63 ^ self.bits_left;
+ // offset position
+ self.position += (num >> 3) as usize;
+ // shift number of bits
+ self.buffer |= new_buffer << self.bits_left;
+ // update bits left
+ // bits left are now between 56-63
+ self.bits_left |= 56;
+ }
+ None => self.refill_slow()
+ }
+ }
+ #[inline(always)]
+ pub fn refill_inner_loop(&mut self)
+ {
+ /*
+ * The refill always guarantees refills between 56-63
+ *
+ * Bits stored will never go above 63 and if bits are in the range 56-63 no refills occur.
+ */
+ let mut buf = [0; 8];
+
+ if let Some(bytes) = self.src.get(self.position..self.position + 8)
+ {
+ {
+ buf.copy_from_slice(bytes);
+ // create a u64 from an array of u8's
+ let new_buffer = u64::from_le_bytes(buf);
+ // num indicates how many bytes we actually consumed.
+ let num = 63 ^ self.bits_left;
+ // offset position
+ self.position += (num >> 3) as usize;
+ // shift number of bits
+ self.buffer |= new_buffer << self.bits_left;
+ // update bits left
+ // bits left are now between 56-63
+ self.bits_left |= 56;
+ }
+ }
+ }
+ #[inline(never)]
+ fn refill_slow(&mut self)
+ {
+ let bytes = &self.src[self.position..];
+
+ for byte in bytes
+ {
+ if self.bits_left >= 56
+ {
+ break;
+ }
+
+ self.buffer |= u64::from(*byte) << self.bits_left;
+ self.bits_left += 8;
+ self.position += 1;
+ }
+ while self.bits_left < 56
+ {
+ self.bits_left += 8;
+ self.over_read += 1;
+ }
+ }
+
+ #[inline(always)]
+ pub fn peek_bits<const LOOKAHEAD: usize>(&self) -> usize
+ {
+ debug_assert!(self.bits_left >= LOOKAHEAD as u8);
+ (self.buffer & ((1 << LOOKAHEAD) - 1)) as usize
+ }
+ #[inline(always)]
+ pub fn peek_var_bits(&self, lookahead: usize) -> usize
+ {
+ debug_assert!(self.bits_left >= lookahead as u8);
+ (self.buffer & ((1 << lookahead) - 1)) as usize
+ }
+
+ #[inline(always)]
+ pub fn get_bits(&mut self, num_bits: u8) -> u64
+ {
+ debug_assert!(self.bits_left >= num_bits);
+
+ let mask = (1_u64 << num_bits) - 1;
+
+ let value = self.buffer & mask;
+
+ self.buffer >>= num_bits;
+
+ self.bits_left -= num_bits;
+
+ value
+ }
+ /// Get number of bits left in the bit buffer.
+ pub const fn get_bits_left(&self) -> u8
+ {
+ self.bits_left
+ }
+ /// Get position the stream is in this buffer
+ /// Or alternatively, number of bits read.
+ pub fn get_position(&self) -> usize
+ {
+ self.position
+ .saturating_sub(usize::from(self.bits_left >> 3))
+ }
+
+ /// Reset buffer and bits left to zero.
+ pub fn reset(&mut self)
+ {
+ self.buffer = 0;
+ self.bits_left = 0;
+ }
+ /// Return true if the bit buffer can satisfy
+ /// `bits` read without refilling,
+ pub const fn has(&self, bits: u8) -> bool
+ {
+ self.bits_left >= bits
+ }
+
+ #[inline(always)]
+ pub fn drop_bits(&mut self, bits: u8)
+ {
+ debug_assert!(self.bits_left >= bits);
+ self.bits_left -= bits;
+ self.buffer >>= bits;
+ }
+ /// Return the remaining bytes in this stream.
+ ///
+ /// This does not consider bits in the bit-buffer hence
+ /// may not be accurate
+ pub const fn remaining_bytes(&self) -> usize
+ {
+ self.src.len().saturating_sub(self.position)
+ }
+}