diff options
author | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
---|---|---|
committer | Valentin Popov <valentin@popov.link> | 2024-01-08 00:21:28 +0300 |
commit | 1b6a04ca5504955c571d1c97504fb45ea0befee4 (patch) | |
tree | 7579f518b23313e8a9748a88ab6173d5e030b227 /vendor/image/src/codecs/webp/lossless.rs | |
parent | 5ecd8cf2cba827454317368b68571df0d13d7842 (diff) | |
download | fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.tar.xz fparkan-1b6a04ca5504955c571d1c97504fb45ea0befee4.zip |
Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
Diffstat (limited to 'vendor/image/src/codecs/webp/lossless.rs')
-rw-r--r-- | vendor/image/src/codecs/webp/lossless.rs | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/vendor/image/src/codecs/webp/lossless.rs b/vendor/image/src/codecs/webp/lossless.rs new file mode 100644 index 0000000..7271eda --- /dev/null +++ b/vendor/image/src/codecs/webp/lossless.rs @@ -0,0 +1,783 @@ +//! Decoding of lossless WebP images +//! +//! [Lossless spec](https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification) +//! + +use std::{ + convert::TryFrom, + convert::TryInto, + error, fmt, + io::Read, + ops::{AddAssign, Shl}, +}; + +use byteorder::ReadBytesExt; + +use crate::{error::DecodingError, ImageError, ImageFormat, ImageResult}; + +use super::huffman::HuffmanTree; +use super::lossless_transform::{add_pixels, TransformType}; + +const CODE_LENGTH_CODES: usize = 19; +const CODE_LENGTH_CODE_ORDER: [usize; CODE_LENGTH_CODES] = [ + 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, +]; + +#[rustfmt::skip] +const DISTANCE_MAP: [(i8, i8); 120] = [ + (0, 1), (1, 0), (1, 1), (-1, 1), (0, 2), (2, 0), (1, 2), (-1, 2), + (2, 1), (-2, 1), (2, 2), (-2, 2), (0, 3), (3, 0), (1, 3), (-1, 3), + (3, 1), (-3, 1), (2, 3), (-2, 3), (3, 2), (-3, 2), (0, 4), (4, 0), + (1, 4), (-1, 4), (4, 1), (-4, 1), (3, 3), (-3, 3), (2, 4), (-2, 4), + (4, 2), (-4, 2), (0, 5), (3, 4), (-3, 4), (4, 3), (-4, 3), (5, 0), + (1, 5), (-1, 5), (5, 1), (-5, 1), (2, 5), (-2, 5), (5, 2), (-5, 2), + (4, 4), (-4, 4), (3, 5), (-3, 5), (5, 3), (-5, 3), (0, 6), (6, 0), + (1, 6), (-1, 6), (6, 1), (-6, 1), (2, 6), (-2, 6), (6, 2), (-6, 2), + (4, 5), (-4, 5), (5, 4), (-5, 4), (3, 6), (-3, 6), (6, 3), (-6, 3), + (0, 7), (7, 0), (1, 7), (-1, 7), (5, 5), (-5, 5), (7, 1), (-7, 1), + (4, 6), (-4, 6), (6, 4), (-6, 4), (2, 7), (-2, 7), (7, 2), (-7, 2), + (3, 7), (-3, 7), (7, 3), (-7, 3), (5, 6), (-5, 6), (6, 5), (-6, 5), + (8, 0), (4, 7), (-4, 7), (7, 4), (-7, 4), (8, 1), (8, 2), (6, 6), + (-6, 6), (8, 3), (5, 7), (-5, 7), (7, 5), (-7, 5), (8, 4), (6, 7), + (-6, 7), (7, 6), (-7, 6), (8, 5), (7, 7), (-7, 7), (8, 6), (8, 7) +]; + +const GREEN: usize = 0; +const RED: usize = 1; +const BLUE: usize = 2; +const ALPHA: usize = 3; +const DIST: usize = 4; + +const HUFFMAN_CODES_PER_META_CODE: usize = 5; + +type HuffmanCodeGroup = [HuffmanTree; HUFFMAN_CODES_PER_META_CODE]; + +const ALPHABET_SIZE: [u16; HUFFMAN_CODES_PER_META_CODE] = [256 + 24, 256, 256, 256, 40]; + +#[inline] +pub(crate) fn subsample_size(size: u16, bits: u8) -> u16 { + ((u32::from(size) + (1u32 << bits) - 1) >> bits) + .try_into() + .unwrap() +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum DecoderError { + /// Signature of 0x2f not found + LosslessSignatureInvalid(u8), + /// Version Number must be 0 + VersionNumberInvalid(u8), + + /// + InvalidColorCacheBits(u8), + + HuffmanError, + + BitStreamError, + + TransformError, +} + +impl fmt::Display for DecoderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DecoderError::LosslessSignatureInvalid(sig) => { + f.write_fmt(format_args!("Invalid lossless signature: {}", sig)) + } + DecoderError::VersionNumberInvalid(num) => { + f.write_fmt(format_args!("Invalid version number: {}", num)) + } + DecoderError::InvalidColorCacheBits(num) => f.write_fmt(format_args!( + "Invalid color cache(must be between 1-11): {}", + num + )), + DecoderError::HuffmanError => f.write_fmt(format_args!("Error building Huffman Tree")), + DecoderError::BitStreamError => { + f.write_fmt(format_args!("Error while reading bitstream")) + } + DecoderError::TransformError => { + f.write_fmt(format_args!("Error while reading or writing transforms")) + } + } + } +} + +impl From<DecoderError> for ImageError { + fn from(e: DecoderError) -> ImageError { + ImageError::Decoding(DecodingError::new(ImageFormat::WebP.into(), e)) + } +} + +impl error::Error for DecoderError {} + +const NUM_TRANSFORM_TYPES: usize = 4; + +//Decodes lossless WebP images +#[derive(Debug)] +pub(crate) struct LosslessDecoder<R> { + r: R, + bit_reader: BitReader, + frame: LosslessFrame, + transforms: [Option<TransformType>; NUM_TRANSFORM_TYPES], + transform_order: Vec<u8>, +} + +impl<R: Read> LosslessDecoder<R> { + /// Create a new decoder + pub(crate) fn new(r: R) -> LosslessDecoder<R> { + LosslessDecoder { + r, + bit_reader: BitReader::new(), + frame: Default::default(), + transforms: [None, None, None, None], + transform_order: Vec::new(), + } + } + + /// Reads the frame + pub(crate) fn decode_frame(&mut self) -> ImageResult<&LosslessFrame> { + let signature = self.r.read_u8()?; + + if signature != 0x2f { + return Err(DecoderError::LosslessSignatureInvalid(signature).into()); + } + + let mut buf = Vec::new(); + self.r.read_to_end(&mut buf)?; + self.bit_reader.init(buf); + + self.frame.width = self.bit_reader.read_bits::<u16>(14)? + 1; + self.frame.height = self.bit_reader.read_bits::<u16>(14)? + 1; + + let _alpha_used = self.bit_reader.read_bits::<u8>(1)?; + + let version_num = self.bit_reader.read_bits::<u8>(3)?; + + if version_num != 0 { + return Err(DecoderError::VersionNumberInvalid(version_num).into()); + } + + let mut data = self.decode_image_stream(self.frame.width, self.frame.height, true)?; + + for &trans_index in self.transform_order.iter().rev() { + let trans = self.transforms[usize::from(trans_index)].as_ref().unwrap(); + trans.apply_transform(&mut data, self.frame.width, self.frame.height)?; + } + + self.frame.buf = data; + Ok(&self.frame) + } + + //used for alpha data in extended decoding + pub(crate) fn decode_frame_implicit_dims( + &mut self, + width: u16, + height: u16, + ) -> ImageResult<&LosslessFrame> { + let mut buf = Vec::new(); + self.r.read_to_end(&mut buf)?; + self.bit_reader.init(buf); + + self.frame.width = width; + self.frame.height = height; + + let mut data = self.decode_image_stream(self.frame.width, self.frame.height, true)?; + + //transform_order is vector of indices(0-3) into transforms in order decoded + for &trans_index in self.transform_order.iter().rev() { + let trans = self.transforms[usize::from(trans_index)].as_ref().unwrap(); + trans.apply_transform(&mut data, self.frame.width, self.frame.height)?; + } + + self.frame.buf = data; + Ok(&self.frame) + } + + /// Reads Image data from the bitstream + /// Can be in any of the 5 roles described in the Specification + /// ARGB Image role has different behaviour to the other 4 + /// xsize and ysize describe the size of the blocks where each block has its own entropy code + fn decode_image_stream( + &mut self, + xsize: u16, + ysize: u16, + is_argb_img: bool, + ) -> ImageResult<Vec<u32>> { + let trans_xsize = if is_argb_img { + self.read_transforms()? + } else { + xsize + }; + + let color_cache_bits = self.read_color_cache()?; + + let color_cache = color_cache_bits.map(|bits| { + let size = 1 << bits; + let cache = vec![0u32; size]; + ColorCache { + color_cache_bits: bits, + color_cache: cache, + } + }); + + let huffman_info = self.read_huffman_codes(is_argb_img, trans_xsize, ysize, color_cache)?; + + //decode data + let data = self.decode_image_data(trans_xsize, ysize, huffman_info)?; + + Ok(data) + } + + /// Reads transforms and their data from the bitstream + fn read_transforms(&mut self) -> ImageResult<u16> { + let mut xsize = self.frame.width; + + while self.bit_reader.read_bits::<u8>(1)? == 1 { + let transform_type_val = self.bit_reader.read_bits::<u8>(2)?; + + if self.transforms[usize::from(transform_type_val)].is_some() { + //can only have one of each transform, error + return Err(DecoderError::TransformError.into()); + } + + self.transform_order.push(transform_type_val); + + let transform_type = match transform_type_val { + 0 => { + //predictor + + let size_bits = self.bit_reader.read_bits::<u8>(3)? + 2; + + let block_xsize = subsample_size(xsize, size_bits); + let block_ysize = subsample_size(self.frame.height, size_bits); + + let data = self.decode_image_stream(block_xsize, block_ysize, false)?; + + TransformType::PredictorTransform { + size_bits, + predictor_data: data, + } + } + 1 => { + //color transform + + let size_bits = self.bit_reader.read_bits::<u8>(3)? + 2; + + let block_xsize = subsample_size(xsize, size_bits); + let block_ysize = subsample_size(self.frame.height, size_bits); + + let data = self.decode_image_stream(block_xsize, block_ysize, false)?; + + TransformType::ColorTransform { + size_bits, + transform_data: data, + } + } + 2 => { + //subtract green + + TransformType::SubtractGreen + } + 3 => { + let color_table_size = self.bit_reader.read_bits::<u16>(8)? + 1; + + let mut color_map = self.decode_image_stream(color_table_size, 1, false)?; + + let bits = if color_table_size <= 2 { + 3 + } else if color_table_size <= 4 { + 2 + } else if color_table_size <= 16 { + 1 + } else { + 0 + }; + xsize = subsample_size(xsize, bits); + + Self::adjust_color_map(&mut color_map); + + TransformType::ColorIndexingTransform { + table_size: color_table_size, + table_data: color_map, + } + } + _ => unreachable!(), + }; + + self.transforms[usize::from(transform_type_val)] = Some(transform_type); + } + + Ok(xsize) + } + + /// Adjusts the color map since it's subtraction coded + fn adjust_color_map(color_map: &mut Vec<u32>) { + for i in 1..color_map.len() { + color_map[i] = add_pixels(color_map[i], color_map[i - 1]); + } + } + + /// Reads huffman codes associated with an image + fn read_huffman_codes( + &mut self, + read_meta: bool, + xsize: u16, + ysize: u16, + color_cache: Option<ColorCache>, + ) -> ImageResult<HuffmanInfo> { + let mut num_huff_groups = 1; + + let mut huffman_bits = 0; + let mut huffman_xsize = 1; + let mut huffman_ysize = 1; + let mut entropy_image = Vec::new(); + + if read_meta && self.bit_reader.read_bits::<u8>(1)? == 1 { + //meta huffman codes + huffman_bits = self.bit_reader.read_bits::<u8>(3)? + 2; + huffman_xsize = subsample_size(xsize, huffman_bits); + huffman_ysize = subsample_size(ysize, huffman_bits); + + entropy_image = self.decode_image_stream(huffman_xsize, huffman_ysize, false)?; + + for pixel in entropy_image.iter_mut() { + let meta_huff_code = (*pixel >> 8) & 0xffff; + + *pixel = meta_huff_code; + + if meta_huff_code >= num_huff_groups { + num_huff_groups = meta_huff_code + 1; + } + } + } + + let mut hufftree_groups = Vec::new(); + + for _i in 0..num_huff_groups { + let mut group: HuffmanCodeGroup = Default::default(); + for j in 0..HUFFMAN_CODES_PER_META_CODE { + let mut alphabet_size = ALPHABET_SIZE[j]; + if j == 0 { + if let Some(color_cache) = color_cache.as_ref() { + alphabet_size += 1 << color_cache.color_cache_bits; + } + } + + let tree = self.read_huffman_code(alphabet_size)?; + group[j] = tree; + } + hufftree_groups.push(group); + } + + let huffman_mask = if huffman_bits == 0 { + !0 + } else { + (1 << huffman_bits) - 1 + }; + + let info = HuffmanInfo { + xsize: huffman_xsize, + _ysize: huffman_ysize, + color_cache, + image: entropy_image, + bits: huffman_bits, + mask: huffman_mask, + huffman_code_groups: hufftree_groups, + }; + + Ok(info) + } + + /// Decodes and returns a single huffman tree + fn read_huffman_code(&mut self, alphabet_size: u16) -> ImageResult<HuffmanTree> { + let simple = self.bit_reader.read_bits::<u8>(1)? == 1; + + if simple { + let num_symbols = self.bit_reader.read_bits::<u8>(1)? + 1; + + let mut code_lengths = vec![u16::from(num_symbols - 1)]; + let mut codes = vec![0]; + let mut symbols = Vec::new(); + + let is_first_8bits = self.bit_reader.read_bits::<u8>(1)?; + symbols.push(self.bit_reader.read_bits::<u16>(1 + 7 * is_first_8bits)?); + + if num_symbols == 2 { + symbols.push(self.bit_reader.read_bits::<u16>(8)?); + code_lengths.push(1); + codes.push(1); + } + + HuffmanTree::build_explicit(code_lengths, codes, symbols) + } else { + let mut code_length_code_lengths = vec![0; CODE_LENGTH_CODES]; + + let num_code_lengths = 4 + self.bit_reader.read_bits::<usize>(4)?; + for i in 0..num_code_lengths { + code_length_code_lengths[CODE_LENGTH_CODE_ORDER[i]] = + self.bit_reader.read_bits(3)?; + } + + let new_code_lengths = + self.read_huffman_code_lengths(code_length_code_lengths, alphabet_size)?; + + HuffmanTree::build_implicit(new_code_lengths) + } + } + + /// Reads huffman code lengths + fn read_huffman_code_lengths( + &mut self, + code_length_code_lengths: Vec<u16>, + num_symbols: u16, + ) -> ImageResult<Vec<u16>> { + let table = HuffmanTree::build_implicit(code_length_code_lengths)?; + + let mut max_symbol = if self.bit_reader.read_bits::<u8>(1)? == 1 { + let length_nbits = 2 + 2 * self.bit_reader.read_bits::<u8>(3)?; + 2 + self.bit_reader.read_bits::<u16>(length_nbits)? + } else { + num_symbols + }; + + let mut code_lengths = vec![0; usize::from(num_symbols)]; + let mut prev_code_len = 8; //default code length + + let mut symbol = 0; + while symbol < num_symbols { + if max_symbol == 0 { + break; + } + max_symbol -= 1; + + let code_len = table.read_symbol(&mut self.bit_reader)?; + + if code_len < 16 { + code_lengths[usize::from(symbol)] = code_len; + symbol += 1; + if code_len != 0 { + prev_code_len = code_len; + } + } else { + let use_prev = code_len == 16; + let slot = code_len - 16; + let extra_bits = match slot { + 0 => 2, + 1 => 3, + 2 => 7, + _ => return Err(DecoderError::BitStreamError.into()), + }; + let repeat_offset = match slot { + 0 | 1 => 3, + 2 => 11, + _ => return Err(DecoderError::BitStreamError.into()), + }; + + let mut repeat = self.bit_reader.read_bits::<u16>(extra_bits)? + repeat_offset; + + if symbol + repeat > num_symbols { + return Err(DecoderError::BitStreamError.into()); + } else { + let length = if use_prev { prev_code_len } else { 0 }; + while repeat > 0 { + repeat -= 1; + code_lengths[usize::from(symbol)] = length; + symbol += 1; + } + } + } + } + + Ok(code_lengths) + } + + /// Decodes the image data using the huffman trees and either of the 3 methods of decoding + fn decode_image_data( + &mut self, + width: u16, + height: u16, + mut huffman_info: HuffmanInfo, + ) -> ImageResult<Vec<u32>> { + let num_values = usize::from(width) * usize::from(height); + let mut data = vec![0; num_values]; + + let huff_index = huffman_info.get_huff_index(0, 0); + let mut tree = &huffman_info.huffman_code_groups[huff_index]; + let mut last_cached = 0; + let mut index = 0; + let mut x = 0; + let mut y = 0; + while index < num_values { + if (x & huffman_info.mask) == 0 { + let index = huffman_info.get_huff_index(x, y); + tree = &huffman_info.huffman_code_groups[index]; + } + + let code = tree[GREEN].read_symbol(&mut self.bit_reader)?; + + //check code + if code < 256 { + //literal, so just use huffman codes and read as argb + let red = tree[RED].read_symbol(&mut self.bit_reader)?; + let blue = tree[BLUE].read_symbol(&mut self.bit_reader)?; + let alpha = tree[ALPHA].read_symbol(&mut self.bit_reader)?; + + data[index] = (u32::from(alpha) << 24) + + (u32::from(red) << 16) + + (u32::from(code) << 8) + + u32::from(blue); + + index += 1; + x += 1; + if x >= width { + x = 0; + y += 1; + } + } else if code < 256 + 24 { + //backward reference, so go back and use that to add image data + let length_symbol = code - 256; + let length = Self::get_copy_distance(&mut self.bit_reader, length_symbol)?; + + let dist_symbol = tree[DIST].read_symbol(&mut self.bit_reader)?; + let dist_code = Self::get_copy_distance(&mut self.bit_reader, dist_symbol)?; + let dist = Self::plane_code_to_distance(width, dist_code); + + if index < dist || num_values - index < length { + return Err(DecoderError::BitStreamError.into()); + } + + for i in 0..length { + data[index + i] = data[index + i - dist]; + } + index += length; + x += u16::try_from(length).unwrap(); + while x >= width { + x -= width; + y += 1; + } + if index < num_values { + let index = huffman_info.get_huff_index(x, y); + tree = &huffman_info.huffman_code_groups[index]; + } + } else { + //color cache, so use previously stored pixels to get this pixel + let key = code - 256 - 24; + + if let Some(color_cache) = huffman_info.color_cache.as_mut() { + //cache old colors + while last_cached < index { + color_cache.insert(data[last_cached]); + last_cached += 1; + } + data[index] = color_cache.lookup(key.into())?; + } else { + return Err(DecoderError::BitStreamError.into()); + } + index += 1; + x += 1; + if x >= width { + x = 0; + y += 1; + } + } + } + + Ok(data) + } + + /// Reads color cache data from the bitstream + fn read_color_cache(&mut self) -> ImageResult<Option<u8>> { + if self.bit_reader.read_bits::<u8>(1)? == 1 { + let code_bits = self.bit_reader.read_bits::<u8>(4)?; + + if !(1..=11).contains(&code_bits) { + return Err(DecoderError::InvalidColorCacheBits(code_bits).into()); + } + + Ok(Some(code_bits)) + } else { + Ok(None) + } + } + + /// Gets the copy distance from the prefix code and bitstream + fn get_copy_distance(bit_reader: &mut BitReader, prefix_code: u16) -> ImageResult<usize> { + if prefix_code < 4 { + return Ok(usize::from(prefix_code + 1)); + } + let extra_bits: u8 = ((prefix_code - 2) >> 1).try_into().unwrap(); + let offset = (2 + (usize::from(prefix_code) & 1)) << extra_bits; + + Ok(offset + bit_reader.read_bits::<usize>(extra_bits)? + 1) + } + + /// Gets distance to pixel + fn plane_code_to_distance(xsize: u16, plane_code: usize) -> usize { + if plane_code > 120 { + plane_code - 120 + } else { + let (xoffset, yoffset) = DISTANCE_MAP[plane_code - 1]; + + let dist = i32::from(xoffset) + i32::from(yoffset) * i32::from(xsize); + if dist < 1 { + return 1; + } + dist.try_into().unwrap() + } + } +} + +#[derive(Debug, Clone)] +struct HuffmanInfo { + xsize: u16, + _ysize: u16, + color_cache: Option<ColorCache>, + image: Vec<u32>, + bits: u8, + mask: u16, + huffman_code_groups: Vec<HuffmanCodeGroup>, +} + +impl HuffmanInfo { + fn get_huff_index(&self, x: u16, y: u16) -> usize { + if self.bits == 0 { + return 0; + } + let position = usize::from((y >> self.bits) * self.xsize + (x >> self.bits)); + let meta_huff_code: usize = self.image[position].try_into().unwrap(); + meta_huff_code + } +} + +#[derive(Debug, Clone)] +struct ColorCache { + color_cache_bits: u8, + color_cache: Vec<u32>, +} + +impl ColorCache { + fn insert(&mut self, color: u32) { + let index = (0x1e35a7bdu32.overflowing_mul(color).0) >> (32 - self.color_cache_bits); + self.color_cache[index as usize] = color; + } + + fn lookup(&self, index: usize) -> ImageResult<u32> { + match self.color_cache.get(index) { + Some(&value) => Ok(value), + None => Err(DecoderError::BitStreamError.into()), + } + } +} + +#[derive(Debug, Clone)] +pub(crate) struct BitReader { + buf: Vec<u8>, + index: usize, + bit_count: u8, +} + +impl BitReader { + fn new() -> BitReader { + BitReader { + buf: Vec::new(), + index: 0, + bit_count: 0, + } + } + + fn init(&mut self, buf: Vec<u8>) { + self.buf = buf; + } + + pub(crate) fn read_bits<T>(&mut self, num: u8) -> ImageResult<T> + where + T: num_traits::Unsigned + Shl<u8, Output = T> + AddAssign<T> + From<bool>, + { + let mut value: T = T::zero(); + + for i in 0..num { + if self.buf.len() <= self.index { + return Err(DecoderError::BitStreamError.into()); + } + let bit_true = self.buf[self.index] & (1 << self.bit_count) != 0; + value += T::from(bit_true) << i; + self.bit_count = if self.bit_count == 7 { + self.index += 1; + 0 + } else { + self.bit_count + 1 + }; + } + + Ok(value) + } +} + +#[derive(Debug, Clone, Default)] +pub(crate) struct LosslessFrame { + pub(crate) width: u16, + pub(crate) height: u16, + + pub(crate) buf: Vec<u32>, +} + +impl LosslessFrame { + /// Fills a buffer by converting from argb to rgba + pub(crate) fn fill_rgba(&self, buf: &mut [u8]) { + for (&argb_val, chunk) in self.buf.iter().zip(buf.chunks_exact_mut(4)) { + chunk[0] = ((argb_val >> 16) & 0xff).try_into().unwrap(); + chunk[1] = ((argb_val >> 8) & 0xff).try_into().unwrap(); + chunk[2] = (argb_val & 0xff).try_into().unwrap(); + chunk[3] = ((argb_val >> 24) & 0xff).try_into().unwrap(); + } + } + + /// Get buffer size from the image + pub(crate) fn get_buf_size(&self) -> usize { + usize::from(self.width) * usize::from(self.height) * 4 + } + + /// Fills a buffer with just the green values from the lossless decoding + /// Used in extended alpha decoding + pub(crate) fn fill_green(&self, buf: &mut [u8]) { + for (&argb_val, buf_value) in self.buf.iter().zip(buf.iter_mut()) { + *buf_value = ((argb_val >> 8) & 0xff).try_into().unwrap(); + } + } +} + +#[cfg(test)] +mod test { + + use super::BitReader; + + #[test] + fn bit_read_test() { + let mut bit_reader = BitReader::new(); + + //10011100 01000001 11100001 + let buf = vec![0x9C, 0x41, 0xE1]; + + bit_reader.init(buf); + + assert_eq!(bit_reader.read_bits::<u8>(3).unwrap(), 4); //100 + assert_eq!(bit_reader.read_bits::<u8>(2).unwrap(), 3); //11 + assert_eq!(bit_reader.read_bits::<u8>(6).unwrap(), 12); //001100 + assert_eq!(bit_reader.read_bits::<u16>(10).unwrap(), 40); //0000101000 + assert_eq!(bit_reader.read_bits::<u8>(3).unwrap(), 7); //111 + } + + #[test] + fn bit_read_error_test() { + let mut bit_reader = BitReader::new(); + + //01101010 + let buf = vec![0x6A]; + + bit_reader.init(buf); + + assert_eq!(bit_reader.read_bits::<u8>(3).unwrap(), 2); //010 + assert_eq!(bit_reader.read_bits::<u8>(5).unwrap(), 13); //01101 + assert!(bit_reader.read_bits::<u8>(4).is_err()); //error + } +} |