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/zune-inflate/src/decoder.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/zune-inflate/src/decoder.rs')
-rw-r--r-- | vendor/zune-inflate/src/decoder.rs | 1791 |
1 files changed, 1791 insertions, 0 deletions
diff --git a/vendor/zune-inflate/src/decoder.rs b/vendor/zune-inflate/src/decoder.rs new file mode 100644 index 0000000..105c882 --- /dev/null +++ b/vendor/zune-inflate/src/decoder.rs @@ -0,0 +1,1791 @@ +#![allow(unused_imports)] + +use alloc::vec::Vec; +use alloc::{format, vec}; + +use crate::bitstream::BitStreamReader; +use crate::constants::{ + DEFLATE_BLOCKTYPE_DYNAMIC_HUFFMAN, DEFLATE_BLOCKTYPE_RESERVED, DEFLATE_BLOCKTYPE_STATIC, + DEFLATE_BLOCKTYPE_UNCOMPRESSED, DEFLATE_MAX_CODEWORD_LENGTH, + DEFLATE_MAX_LITLEN_CODEWORD_LENGTH, DEFLATE_MAX_NUM_SYMS, DEFLATE_MAX_OFFSET_CODEWORD_LENGTH, + DEFLATE_MAX_PRE_CODEWORD_LEN, DEFLATE_NUM_LITLEN_SYMS, DEFLATE_NUM_OFFSET_SYMS, + DEFLATE_NUM_PRECODE_SYMS, DEFLATE_PRECODE_LENS_PERMUTATION, DELFATE_MAX_LENS_OVERRUN, + FASTCOPY_BYTES, FASTLOOP_MAX_BYTES_WRITTEN, HUFFDEC_END_OF_BLOCK, HUFFDEC_EXCEPTIONAL, + HUFFDEC_LITERAL, HUFFDEC_SUITABLE_POINTER, LITLEN_DECODE_BITS, LITLEN_DECODE_RESULTS, + LITLEN_ENOUGH, LITLEN_TABLE_BITS, OFFSET_DECODE_RESULTS, OFFSET_ENOUGH, OFFSET_TABLEBITS, + PRECODE_DECODE_RESULTS, PRECODE_ENOUGH, PRECODE_TABLE_BITS +}; +use crate::errors::{DecodeErrorStatus, InflateDecodeErrors}; +#[cfg(feature = "gzip")] +use crate::gzip_constants::{ + GZIP_CM_DEFLATE, GZIP_FCOMMENT, GZIP_FEXTRA, GZIP_FHCRC, GZIP_FNAME, GZIP_FOOTER_SIZE, + GZIP_FRESERVED, GZIP_ID1, GZIP_ID2 +}; +use crate::utils::{copy_rep_matches, fixed_copy_within, make_decode_table_entry}; + +struct DeflateHeaderTables +{ + litlen_decode_table: [u32; LITLEN_ENOUGH], + offset_decode_table: [u32; OFFSET_ENOUGH] +} + +impl Default for DeflateHeaderTables +{ + fn default() -> Self + { + DeflateHeaderTables { + litlen_decode_table: [0; LITLEN_ENOUGH], + offset_decode_table: [0; OFFSET_ENOUGH] + } + } +} + +/// Options that can influence decompression +/// in Deflate/Zlib/Gzip +/// +/// To use them, pass a customized options to +/// the deflate decoder. +#[derive(Copy, Clone)] +pub struct DeflateOptions +{ + limit: usize, + confirm_checksum: bool, + size_hint: usize +} + +impl Default for DeflateOptions +{ + fn default() -> Self + { + DeflateOptions { + limit: 1 << 30, + confirm_checksum: true, + size_hint: 37000 + } + } +} + +impl DeflateOptions +{ + /// Get deflate/zlib limit option + /// + /// The decoder won't extend the inbuilt limit and will + /// return an error if the limit is exceeded + /// + /// # Returns + /// The currently set limit of the instance + /// # Note + /// This is provided as a best effort, correctly quiting + /// is detrimental to speed and hence this should not be relied too much. + pub const fn get_limit(&self) -> usize + { + self.limit + } + /// Set a limit to the internal vector + /// used to store decoded zlib/deflate output. + /// + /// # Arguments + /// limit: The new decompressor limit + /// # Returns + /// A modified version of DeflateDecoder + /// + /// # Note + /// This is provided as a best effort, correctly quiting + /// is detrimental to speed and hence this should not be relied too much + #[must_use] + pub fn set_limit(mut self, limit: usize) -> Self + { + self.limit = limit; + self + } + + /// Get whether the decoder will confirm a checksum + /// after decoding + pub const fn get_confirm_checksum(&self) -> bool + { + self.confirm_checksum + } + /// Set whether the decoder should confirm a checksum + /// after decoding + /// + /// Note, you should definitely confirm your checksum, use + /// this with caution, otherwise data returned may be corrupt + /// + /// # Arguments + /// - yes: When true, the decoder will confirm checksum + /// when false, the decoder will skip checksum verification + /// # Notes + /// This does not have an influence for deflate decoding as + /// it does not have a checksum + pub fn set_confirm_checksum(mut self, yes: bool) -> Self + { + self.confirm_checksum = yes; + self + } + + /// Get the default set size hint for the decompressor + /// + /// The decompressor initializes the internal storage for decompressed bytes + /// with this size and will reallocate the vec if the decompressed size becomes bigger + /// than this, but when the user currently knows how big the output will be, can be used + /// to prevent unnecessary re-allocations + pub const fn get_size_hint(&self) -> usize + { + self.size_hint + } + /// Set the size hint for the decompressor + /// + /// This can be used to prevent multiple re-allocations + #[must_use] + pub const fn set_size_hint(mut self, hint: usize) -> Self + { + self.size_hint = hint; + self + } +} + +/// A deflate decoder instance. +/// +/// The decoder manages output buffer as opposed to requiring the caller to provide a pre-allocated buffer +/// it tracks number of bytes written and on successfully reaching the +/// end of the block, will return a vector with exactly +/// the number of decompressed bytes. +/// +/// This means that it may use up huge amounts of memory if not checked, but +/// there are [options] that can prevent that +/// +/// [options]: DeflateOptions +pub struct DeflateDecoder<'a> +{ + data: &'a [u8], + position: usize, + stream: BitStreamReader<'a>, + is_last_block: bool, + static_codes_loaded: bool, + deflate_header_tables: DeflateHeaderTables, + options: DeflateOptions +} + +impl<'a> DeflateDecoder<'a> +{ + /// Create a new decompressor that will read compressed + /// data from `data` and return a new vector containing new data + /// + /// # Arguments + /// - `data`: The compressed data. Data can be of any type + /// gzip,zlib or raw deflate. + /// + /// # Returns + /// A decoder instance which will pull compressed data from `data` to inflate the output output + /// + /// # Note + /// + /// The default output size limit is **1 GiB.** + /// this is to protect the end user against ddos attacks as deflate does not specify it's + /// output size upfront + /// + /// The checksum will be verified depending on the called function. + /// this only works for zlib and gzip since deflate does not have a checksum + /// + /// These defaults can be overridden via [new_with_options()](Self::new_with_options). + pub fn new(data: &'a [u8]) -> DeflateDecoder<'a> + { + let options = DeflateOptions::default(); + + Self::new_with_options(data, options) + } + /// Create new decoder with specified options + /// + /// This can be used to fine tune the decoder to the user's + /// needs. + /// + /// + /// # Arguments + /// - `data`: The compressed data. Data can be of any format i.e + /// gzip, zlib or raw deflate. + /// - `options` : A set of user defined options which tune how the decompressor + /// + /// # Returns + /// A decoder instance which will pull compressed data from `data` to inflate output + /// + /// # Example + /// ```no_run + /// use zune_inflate::{DeflateDecoder, DeflateOptions}; + /// let data = [37]; + /// let options = DeflateOptions::default() + /// .set_confirm_checksum(true) // confirm the checksum for zlib and gzip + /// .set_limit(1000); // how big I think the input will be + /// let mut decoder = DeflateDecoder::new_with_options(&data,options); + /// // do some stuff and then call decode + /// let data = decoder.decode_zlib(); + /// + /// ``` + pub fn new_with_options(data: &'a [u8], options: DeflateOptions) -> DeflateDecoder<'a> + { + // create stream + DeflateDecoder { + data, + position: 0, + stream: BitStreamReader::new(data), + is_last_block: false, + static_codes_loaded: false, + deflate_header_tables: DeflateHeaderTables::default(), + options + } + } + /// Decode zlib-encoded data returning the uncompressed in a `Vec<u8>` + /// or an error if something went wrong. + /// + /// Bytes consumed will be from the data passed when the + /// `new` method was called. + /// + /// # Arguments + /// - None + /// # Returns + /// Result type containing the decoded data. + /// + /// - `Ok(Vec<u8>)`: Decoded vector containing the uncompressed bytes + /// - `Err(InflateDecodeErrors)`: Error that occurred during decoding + /// + /// It's possible to recover bytes even after an error occurred, bytes up + /// to when error was encountered are stored in [InflateDecodeErrors] + /// + /// + /// # Note + /// This needs the `zlib` feature enabled to be available otherwise it's a + /// compile time error + /// + /// [InflateDecodeErrors]:crate::errors::InflateDecodeErrors + /// + #[cfg(feature = "zlib")] + pub fn decode_zlib(&mut self) -> Result<Vec<u8>, InflateDecodeErrors> + { + use crate::utils::calc_adler_hash; + + if self.data.len() + < 2 /* zlib header */ + + 4 + /* Deflate */ + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::InsufficientData + )); + } + + // Zlib flags + // See https://www.ietf.org/rfc/rfc1950.txt for + // the RFC + let cmf = self.data[0]; + let flg = self.data[1]; + + let cm = cmf & 0xF; + let cinfo = cmf >> 4; + + // let fcheck = flg & 0xF; + // let fdict = (flg >> 4) & 1; + // let flevel = flg >> 5; + + // confirm we have the right deflate methods + if cm != 8 + { + if cm == 15 + { + return Err(InflateDecodeErrors::new_with_error(DecodeErrorStatus::Generic( + "CM of 15 is preserved by the standard,currently don't know how to handle it" + ))); + } + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::GenericStr(format!("Unknown zlib compression method {cm}")) + )); + } + if cinfo > 7 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::GenericStr(format!( + "Unknown cinfo `{cinfo}` greater than 7, not allowed" + )) + )); + } + let flag_checks = (u16::from(cmf) * 256) + u16::from(flg); + + if flag_checks % 31 != 0 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::Generic("FCHECK integrity not preserved") + )); + } + + self.position = 2; + + let data = self.decode_deflate()?; + + if self.options.confirm_checksum + { + // Get number of consumed bytes from the input + let out_pos = self.stream.get_position() + self.position + self.stream.over_read; + + // read adler + if let Some(adler) = self.data.get(out_pos..out_pos + 4) + { + let adler_bits: [u8; 4] = adler.try_into().unwrap(); + + let adler32_expected = u32::from_be_bytes(adler_bits); + + let adler32_found = calc_adler_hash(&data); + + if adler32_expected != adler32_found + { + let err_msg = + DecodeErrorStatus::MismatchedAdler(adler32_expected, adler32_found); + let err = InflateDecodeErrors::new(err_msg, data); + + return Err(err); + } + } + else + { + let err = InflateDecodeErrors::new(DecodeErrorStatus::InsufficientData, data); + + return Err(err); + } + } + + Ok(data) + } + + /// Decode a gzip encoded data and return the uncompressed data in a + /// `Vec<u8>` or an error if something went wrong + /// + /// Bytes consumed will be from the data passed when the + /// `new` method was called. + /// + /// # Arguments + /// - None + /// # Returns + /// Result type containing the decoded data. + /// + /// - `Ok(Vec<u8>)`: Decoded vector containing the uncompressed bytes + /// - `Err(InflateDecodeErrors)`: Error that occurred during decoding + /// + /// It's possible to recover bytes even after an error occurred, bytes up + /// to when error was encountered are stored in [InflateDecodeErrors] + /// + /// # Note + /// This needs the `gzip` feature enabled to be available, otherwise it's a + /// compile time error + /// + /// [InflateDecodeErrors]:crate::errors::InflateDecodeErrors + /// + #[cfg(feature = "gzip")] + pub fn decode_gzip(&mut self) -> Result<Vec<u8>, InflateDecodeErrors> + { + if self.data.len() < 18 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::InsufficientData + )); + } + + if self.data[self.position] != GZIP_ID1 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::CorruptData + )); + } + self.position += 1; + if self.data[self.position] != GZIP_ID2 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::CorruptData + )); + } + self.position += 1; + + if self.data[self.position] != GZIP_CM_DEFLATE + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::CorruptData + )); + } + self.position += 1; + + let flg = self.data[self.position]; + self.position += 1; + + // skip mtime + self.position += 4; + // skip xfl + self.position += 1; + // skip os + self.position += 1; + + if (flg & GZIP_FRESERVED) != 0 + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::CorruptData + )); + } + // extra field + if (flg & GZIP_FEXTRA) != 0 + { + let len_bytes = self.data[self.position..self.position + 2] + .try_into() + .unwrap(); + let xlen = usize::from(u16::from_le_bytes(len_bytes)); + + self.position += 2; + + if self.data.len().saturating_sub(self.position) < xlen + GZIP_FOOTER_SIZE + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::CorruptData + )); + } + self.position += xlen; + } + // original file name zero terminated + if (flg & GZIP_FNAME) != 0 + { + loop + { + if let Some(byte) = self.data.get(self.position) + { + self.position += 1; + + if *byte == 0 + { + break; + } + } + else + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::InsufficientData + )); + } + } + } + // File comment zero terminated + if (flg & GZIP_FCOMMENT) != 0 + { + loop + { + if let Some(byte) = self.data.get(self.position) + { + self.position += 1; + + if *byte == 0 + { + break; + } + } + else + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::InsufficientData + )); + } + } + } + // crc16 for gzip header + if (flg & GZIP_FHCRC) != 0 + { + self.position += 2; + } + + if self.position + GZIP_FOOTER_SIZE > self.data.len() + { + return Err(InflateDecodeErrors::new_with_error( + DecodeErrorStatus::InsufficientData + )); + } + + let data = self.decode_deflate()?; + + let mut out_pos = self.stream.get_position() + self.position + self.stream.over_read; + + if self.options.confirm_checksum + { + // Get number of consumed bytes from the input + + if let Some(crc) = self.data.get(out_pos..out_pos + 4) + { + let crc_bits: [u8; 4] = crc.try_into().unwrap(); + + let crc32_expected = u32::from_le_bytes(crc_bits); + + let crc32_found = !crate::crc::crc32(&data, !0); + + if crc32_expected != crc32_found + { + let err_msg = DecodeErrorStatus::MismatchedCRC(crc32_expected, crc32_found); + let err = InflateDecodeErrors::new(err_msg, data); + + return Err(err); + } + } + else + { + let err = InflateDecodeErrors::new(DecodeErrorStatus::InsufficientData, data); + + return Err(err); + } + } + //checksum + out_pos += 4; + + if let Some(val) = self.data.get(out_pos..out_pos + 4) + { + let actual_bytes: [u8; 4] = val.try_into().unwrap(); + let ac = u32::from_le_bytes(actual_bytes) as usize; + + if data.len() != ac + { + let err = DecodeErrorStatus::Generic("ISIZE does not match actual bytes"); + + let err = InflateDecodeErrors::new(err, data); + + return Err(err); + } + } + else + { + let err = InflateDecodeErrors::new(DecodeErrorStatus::InsufficientData, data); + + return Err(err); + } + + Ok(data) + } + /// Decode a deflate stream returning the data as `Vec<u8>` or an error + /// indicating what went wrong. + /// # Arguments + /// - None + /// # Returns + /// Result type containing the decoded data. + /// + /// - `Ok(Vec<u8>)`: Decoded vector containing the uncompressed bytes + /// - `Err(InflateDecodeErrors)`: Error that occurred during decoding + /// + /// It's possible to recover bytes even after an error occurred, bytes up + /// to when error was encountered are stored in [InflateDecodeErrors] + /// + /// + /// # Example + /// ```no_run + /// let data = [42]; // answer to life, the universe and everything + /// + /// let mut decoder = zune_inflate::DeflateDecoder::new(&data); + /// let bytes = decoder.decode_deflate().unwrap(); + /// ``` + /// + /// [InflateDecodeErrors]:crate::errors::InflateDecodeErrors + pub fn decode_deflate(&mut self) -> Result<Vec<u8>, InflateDecodeErrors> + { + self.start_deflate_block() + } + /// Main inner loop for decompressing deflate data + #[allow(unused_assignments)] + fn start_deflate_block(&mut self) -> Result<Vec<u8>, InflateDecodeErrors> + { + // start deflate decode + // re-read the stream so that we can remove code read by zlib + self.stream = BitStreamReader::new(&self.data[self.position..]); + + self.stream.refill(); + + // Output space for our decoded bytes. + let mut out_block = vec![0; self.options.size_hint]; + // bits used + + let mut src_offset = 0; + let mut dest_offset = 0; + + loop + { + self.stream.refill(); + + self.is_last_block = self.stream.get_bits(1) == 1; + let block_type = self.stream.get_bits(2); + + if block_type == DEFLATE_BLOCKTYPE_UNCOMPRESSED + { + /* + * Uncompressed block: copy 'len' bytes literally from the input + * buffer to the output buffer. + */ + /* + * The RFC says that + * skip any remaining bits in current partially + * processed byte + * read LEN and NLEN (see next section) + * copy LEN bytes of data to output + */ + + if self.stream.over_read > usize::from(self.stream.get_bits_left() >> 3) + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::Generic("over-read stream"); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + let partial_bits = self.stream.get_bits_left() & 7; + + self.stream.drop_bits(partial_bits); + + let len = self.stream.get_bits(16) as u16; + let nlen = self.stream.get_bits(16) as u16; + + // copy to deflate + if len != !nlen + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::Generic("Len and nlen do not match"); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + let len = len as usize; + + let start = self.stream.get_position() + self.position + self.stream.over_read; + + // ensure there is enough space for a fast copy + if dest_offset + len + FASTCOPY_BYTES > out_block.len() + { + // and if there is not, resize + let new_len = out_block.len() + RESIZE_BY + len; + + out_block.resize(new_len, 0); + } + + if self.data.get((start + len).saturating_sub(1)).is_none() + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::CorruptData; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + if dest_offset > self.options.limit + { + out_block.truncate(dest_offset); + + let err_msg = + DecodeErrorStatus::OutputLimitExceeded(self.options.limit, out_block.len()); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + out_block[dest_offset..dest_offset + len] + .copy_from_slice(&self.data[start..start + len]); + + dest_offset += len; + + // get the new position to write. + self.stream.position = + len + (self.stream.position - usize::from(self.stream.bits_left >> 3)); + + self.stream.reset(); + + if self.is_last_block + { + break; + } + + continue; + } + else if block_type == DEFLATE_BLOCKTYPE_RESERVED + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::Generic("Reserved block type 0b11 encountered"); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + // build decode tables for static and dynamic tables + match self.build_decode_table(block_type) + { + Ok(_) => (), + Err(value) => + { + out_block.truncate(dest_offset); + + let err_msg = value; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + }; + + // Tables are mutated into the struct, so at this point we know the tables + // are loaded, take a reference to them + let litlen_decode_table = &self.deflate_header_tables.litlen_decode_table; + let offset_decode_table = &self.deflate_header_tables.offset_decode_table; + + /* + * This is the "fast loop" for decoding literals and matches. It does + * bounds checks on in_next and out_next in the loop conditions so that + * additional bounds checks aren't needed inside the loop body. + * + * To reduce latency, the bit-buffer is refilled and the next litlen + * decode table entry is preloaded before each loop iteration. + */ + let (mut literal, mut length, mut offset, mut entry) = (0, 0, 0, 0); + + let mut saved_bitbuf; + + 'decode: loop + { + let close_src = 3 * FASTCOPY_BYTES < self.stream.remaining_bytes(); + + if close_src + { + self.stream.refill_inner_loop(); + + let lit_mask = self.stream.peek_bits::<LITLEN_DECODE_BITS>(); + + entry = litlen_decode_table[lit_mask]; + + 'sequence: loop + { + // Resize the output vector here to ensure we can always have + // enough space for sloppy copies + if dest_offset + FASTLOOP_MAX_BYTES_WRITTEN > out_block.len() + { + let curr_len = out_block.len(); + out_block.resize(curr_len + FASTLOOP_MAX_BYTES_WRITTEN + RESIZE_BY, 0) + } + // At this point entry contains the next value of the litlen + // This will always be the case so meaning all our exit paths need + // to load in the next entry. + + // recheck after every sequence + // when we hit continue, we need to recheck this + // as we are trying to emulate a do while + let new_check = self.stream.src.len() < self.stream.position + 8; + + if new_check + { + break 'sequence; + } + + self.stream.refill_inner_loop(); + /* + * Consume the bits for the litlen decode table entry. Save the + * original bit-buf for later, in case the extra match length + * bits need to be extracted from it. + */ + saved_bitbuf = self.stream.buffer; + + self.stream.drop_bits((entry & 0xFF) as u8); + + /* + * Begin by checking for a "fast" literal, i.e. a literal that + * doesn't need a subtable. + */ + if (entry & HUFFDEC_LITERAL) != 0 + { + /* + * On 64-bit platforms, we decode up to 2 extra fast + * literals in addition to the primary item, as this + * increases performance and still leaves enough bits + * remaining for what follows. We could actually do 3, + * assuming LITLEN_TABLEBITS=11, but that actually + * decreases performance slightly (perhaps by messing + * with the branch prediction of the conditional refill + * that happens later while decoding the match offset). + */ + + literal = entry >> 16; + + let new_pos = self.stream.peek_bits::<LITLEN_DECODE_BITS>(); + + entry = litlen_decode_table[new_pos]; + saved_bitbuf = self.stream.buffer; + + self.stream.drop_bits(entry as u8); + + let out: &mut [u8; 2] = out_block + .get_mut(dest_offset..dest_offset + 2) + .unwrap() + .try_into() + .unwrap(); + + out[0] = literal as u8; + dest_offset += 1; + + if (entry & HUFFDEC_LITERAL) != 0 + { + /* + * Another fast literal, but this one is in lieu of the + * primary item, so it doesn't count as one of the extras. + */ + + // load in the next entry. + literal = entry >> 16; + + let new_pos = self.stream.peek_bits::<LITLEN_DECODE_BITS>(); + + entry = litlen_decode_table[new_pos]; + + out[1] = literal as u8; + dest_offset += 1; + + continue; + } + } + /* + * It's not a literal entry, so it can be a length entry, a + * subtable pointer entry, or an end-of-block entry. Detect the + * two unlikely cases by testing the HUFFDEC_EXCEPTIONAL flag. + */ + if (entry & HUFFDEC_EXCEPTIONAL) != 0 + { + // Subtable pointer or end of block entry + if (entry & HUFFDEC_END_OF_BLOCK) != 0 + { + // block done + break 'decode; + } + /* + * A subtable is required. Load and consume the + * subtable entry. The subtable entry can be of any + * type: literal, length, or end-of-block. + */ + let entry_position = ((entry >> 8) & 0x3F) as usize; + let mut pos = (entry >> 16) as usize; + + saved_bitbuf = self.stream.buffer; + + pos += self.stream.peek_var_bits(entry_position); + entry = litlen_decode_table[pos.min(LITLEN_ENOUGH - 1)]; + + self.stream.drop_bits(entry as u8); + + if (entry & HUFFDEC_LITERAL) != 0 + { + // decode a literal that required a sub table + let new_pos = self.stream.peek_bits::<LITLEN_DECODE_BITS>(); + + literal = entry >> 16; + entry = litlen_decode_table[new_pos]; + + *out_block.get_mut(dest_offset).unwrap_or(&mut 0) = + (literal & 0xFF) as u8; + + dest_offset += 1; + + continue; + } + + if (entry & HUFFDEC_END_OF_BLOCK) != 0 + { + break 'decode; + } + } + + // At this point,we dropped at most 22 bits(LITLEN_DECODE is 11 and we + // can do it twice), we now just have 34 bits min remaining. + + /* + * Decode the match length: the length base value associated + * with the litlen symbol (which we extract from the decode + * table entry), plus the extra length bits. We don't need to + * consume the extra length bits here, as they were included in + * the bits consumed by the entry earlier. We also don't need + * to check for too-long matches here, as this is inside the + * fast loop where it's already been verified that the output + * buffer has enough space remaining to copy a max-length match. + */ + let entry_dup = entry; + + entry = offset_decode_table[self.stream.peek_bits::<OFFSET_TABLEBITS>()]; + length = (entry_dup >> 16) as usize; + + let mask = (1 << entry_dup as u8) - 1; + + length += (saved_bitbuf & mask) as usize >> ((entry_dup >> 8) as u8); + + // offset requires a subtable + if (entry & HUFFDEC_EXCEPTIONAL) != 0 + { + self.stream.drop_bits(OFFSET_TABLEBITS as u8); + let extra = self.stream.peek_var_bits(((entry >> 8) & 0x3F) as usize); + entry = offset_decode_table[((entry >> 16) as usize + extra) & 511]; + // refill to handle some weird edge case where we have + // less bits than needed for reading the lit-len + } + saved_bitbuf = self.stream.buffer; + + self.stream.drop_bits((entry & 0xFF) as u8); + + let mask = (1 << entry as u8) - 1; + + offset = (entry >> 16) as usize; + offset += (saved_bitbuf & mask) as usize >> (((entry >> 8) & 0xFF) as u8); + + if offset > dest_offset + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::CorruptData; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + src_offset = dest_offset - offset; + + if self.stream.bits_left < 11 + { + self.stream.refill_inner_loop(); + } + // Copy some bytes unconditionally + // This makes us copy smaller match lengths quicker because we don't need + // a loop + don't send too much pressure to the Memory unit. + fixed_copy_within::<FASTCOPY_BYTES>( + &mut out_block, + src_offset, + dest_offset + ); + + entry = litlen_decode_table[self.stream.peek_bits::<LITLEN_DECODE_BITS>()]; + + let mut current_position = dest_offset; + + dest_offset += length; + + if offset == 1 + { + // RLE fill with a single byte + let byte_to_repeat = out_block[src_offset]; + out_block[current_position..dest_offset].fill(byte_to_repeat); + } + else if offset <= FASTCOPY_BYTES + && current_position + offset < dest_offset + { + // The second conditional ensures we only come + // here if the first copy didn't succeed to copy just enough bytes for a rep + // match to be valid, i.e we want this path to be taken the least amount + // of times possible + + // the unconditional copy above copied some bytes + // don't let it go into waste + // Increment the position we are in by the number of correct bytes + // currently copied + let mut src_position = src_offset + offset; + let mut dest_position = current_position + offset; + + // loop copying offset bytes in place + // notice this loop does fixed copies but increments in offset bytes :) + // that is intentional. + loop + { + fixed_copy_within::<FASTCOPY_BYTES>( + &mut out_block, + src_position, + dest_position + ); + + src_position += offset; + dest_position += offset; + + if dest_position > dest_offset + { + break; + } + } + } + else if length > FASTCOPY_BYTES + { + current_position += FASTCOPY_BYTES; + // fast non-overlapping copy + // + // We have enough space to write the ML+FAST_COPY bytes ahead + // so we know this won't come to shoot us in the foot. + // + // An optimization is to copy FAST_COPY_BITS per invocation + // Currently FASTCOPY_BYTES is 16, this fits in nicely as we + // it's a single SIMD instruction on a lot of things, i.e x86,Arm and even + // wasm. + + // current position of the match + let mut dest_src_offset = src_offset + FASTCOPY_BYTES; + + // Number of bytes we are to copy + // copy in batches of FAST_BYTES + 'match_lengths: loop + { + // Safety: We resized out_block hence we know it can handle + // sloppy copies without it being out of bounds + // + // Reason: This is a latency critical loop, even branches start + // to matter + fixed_copy_within::<FASTCOPY_BYTES>( + &mut out_block, + dest_src_offset, + current_position + ); + + dest_src_offset += FASTCOPY_BYTES; + current_position += FASTCOPY_BYTES; + + if current_position > dest_offset + { + break 'match_lengths; + } + } + } + + if dest_offset > self.options.limit + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::OutputLimitExceeded( + self.options.limit, + dest_offset + ); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + if self.stream.src.len() < self.stream.position + 8 + { + // close to input end, move to the slower one + break 'sequence; + } + } + } + // generic loop that does things a bit slower but it's okay since it doesn't + // deal with a lot of things + // We can afford to be more careful here, checking that we do + // not drop non-existent bits etc etc as we do not have the + // assurances of the fast loop bits above. + loop + { + self.stream.refill(); + + if self.stream.over_read > usize::from(self.stream.bits_left >> 3) + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::CorruptData; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + let literal_mask = self.stream.peek_bits::<LITLEN_DECODE_BITS>(); + + entry = litlen_decode_table[literal_mask]; + + saved_bitbuf = self.stream.buffer; + + self.stream.drop_bits((entry & 0xFF) as u8); + + if (entry & HUFFDEC_SUITABLE_POINTER) != 0 + { + let extra = self.stream.peek_var_bits(((entry >> 8) & 0x3F) as usize); + + entry = litlen_decode_table[(entry >> 16) as usize + extra]; + saved_bitbuf = self.stream.buffer; + + self.stream.drop_bits((entry & 0xFF) as u8); + } + + length = (entry >> 16) as usize; + + if (entry & HUFFDEC_LITERAL) != 0 + { + resize_and_push(&mut out_block, dest_offset, length as u8); + + dest_offset += 1; + + continue; + } + + if (entry & HUFFDEC_END_OF_BLOCK) != 0 + { + break 'decode; + } + + let mask = (1 << entry as u8) - 1; + + length += (saved_bitbuf & mask) as usize >> ((entry >> 8) as u8); + + self.stream.refill(); + + entry = offset_decode_table[self.stream.peek_bits::<OFFSET_TABLEBITS>()]; + + if (entry & HUFFDEC_EXCEPTIONAL) != 0 + { + // offset requires a subtable + self.stream.drop_bits(OFFSET_TABLEBITS as u8); + + let extra = self.stream.peek_var_bits(((entry >> 8) & 0x3F) as usize); + + entry = offset_decode_table[((entry >> 16) as usize + extra) & 511]; + } + + // ensure there is enough space for a fast copy + if dest_offset + length + FASTCOPY_BYTES > out_block.len() + { + let new_len = out_block.len() + RESIZE_BY + length; + out_block.resize(new_len, 0); + } + saved_bitbuf = self.stream.buffer; + + let mask = (1 << (entry & 0xFF) as u8) - 1; + + offset = (entry >> 16) as usize; + offset += (saved_bitbuf & mask) as usize >> ((entry >> 8) as u8); + + if offset > dest_offset + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::CorruptData; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + src_offset = dest_offset - offset; + + self.stream.drop_bits(entry as u8); + + let (dest_src, dest_ptr) = out_block.split_at_mut(dest_offset); + + if src_offset + length + FASTCOPY_BYTES > dest_offset + { + // overlapping copy + // do a simple rep match + copy_rep_matches(&mut out_block, src_offset, dest_offset, length); + } + else + { + dest_ptr[0..length] + .copy_from_slice(&dest_src[src_offset..src_offset + length]); + } + + dest_offset += length; + + if dest_offset > self.options.limit + { + out_block.truncate(dest_offset); + + let err_msg = + DecodeErrorStatus::OutputLimitExceeded(self.options.limit, dest_offset); + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + } + } + /* + * If any of the implicit appended zero bytes were consumed (not just + * refilled) before hitting end of stream, then the data is bad. + */ + if self.stream.over_read > usize::from(self.stream.bits_left >> 3) + { + out_block.truncate(dest_offset); + + let err_msg = DecodeErrorStatus::CorruptData; + let error = InflateDecodeErrors::new(err_msg, out_block); + + return Err(error); + } + + if self.is_last_block + { + break; + } + } + + // decompression. DONE + // Truncate data to match the number of actual + // bytes written. + out_block.truncate(dest_offset); + + Ok(out_block) + } + + /// Build decode tables for static and dynamic + /// huffman blocks. + fn build_decode_table(&mut self, block_type: u64) -> Result<(), DecodeErrorStatus> + { + const COUNT: usize = + DEFLATE_NUM_LITLEN_SYMS + DEFLATE_NUM_OFFSET_SYMS + DELFATE_MAX_LENS_OVERRUN; + + let mut lens = [0_u8; COUNT]; + let mut precode_lens = [0; DEFLATE_NUM_PRECODE_SYMS]; + let mut precode_decode_table = [0_u32; PRECODE_ENOUGH]; + let mut litlen_decode_table = [0_u32; LITLEN_ENOUGH]; + let mut offset_decode_table = [0; OFFSET_ENOUGH]; + + let mut num_litlen_syms = 0; + let mut num_offset_syms = 0; + + if block_type == DEFLATE_BLOCKTYPE_DYNAMIC_HUFFMAN + { + const SINGLE_PRECODE: usize = 3; + + self.static_codes_loaded = false; + + // Dynamic Huffman block + // Read codeword lengths + if !self.stream.has(5 + 5 + 4) + { + return Err(DecodeErrorStatus::InsufficientData); + } + + num_litlen_syms = 257 + (self.stream.get_bits(5)) as usize; + num_offset_syms = 1 + (self.stream.get_bits(5)) as usize; + + let num_explicit_precode_lens = 4 + (self.stream.get_bits(4)) as usize; + + self.stream.refill(); + + if !self.stream.has(3) + { + return Err(DecodeErrorStatus::InsufficientData); + } + + let first_precode = self.stream.get_bits(3) as u8; + let expected = (SINGLE_PRECODE * num_explicit_precode_lens.saturating_sub(1)) as u8; + + precode_lens[usize::from(DEFLATE_PRECODE_LENS_PERMUTATION[0])] = first_precode; + + self.stream.refill(); + + if !self.stream.has(expected) + { + return Err(DecodeErrorStatus::InsufficientData); + } + + for i in DEFLATE_PRECODE_LENS_PERMUTATION[1..] + .iter() + .take(num_explicit_precode_lens - 1) + { + let bits = self.stream.get_bits(3) as u8; + + precode_lens[usize::from(*i)] = bits; + } + + self.build_decode_table_inner( + &precode_lens, + &PRECODE_DECODE_RESULTS, + &mut precode_decode_table, + PRECODE_TABLE_BITS, + DEFLATE_NUM_PRECODE_SYMS, + DEFLATE_MAX_CODEWORD_LENGTH + )?; + + /* Decode the litlen and offset codeword lengths. */ + + let mut i = 0; + + loop + { + if i >= num_litlen_syms + num_offset_syms + { + // confirm here since with a continue loop stuff + // breaks + break; + } + + let rep_val: u8; + let rep_count: u64; + + if !self.stream.has(DEFLATE_MAX_PRE_CODEWORD_LEN + 7) + { + self.stream.refill(); + } + // decode next pre-code symbol + let entry_pos = self + .stream + .peek_bits::<{ DEFLATE_MAX_PRE_CODEWORD_LEN as usize }>(); + + let entry = precode_decode_table[entry_pos]; + let presym = entry >> 16; + + if !self.stream.has(entry as u8) + { + return Err(DecodeErrorStatus::InsufficientData); + } + + self.stream.drop_bits(entry as u8); + + if presym < 16 + { + // explicit codeword length + lens[i] = presym as u8; + i += 1; + continue; + } + + /* Run-length encoded codeword lengths */ + + /* + * Note: we don't need verify that the repeat count + * doesn't overflow the number of elements, since we've + * sized the lens array to have enough extra space to + * allow for the worst-case overrun (138 zeroes when + * only 1 length was remaining). + * + * In the case of the small repeat counts (presyms 16 + * and 17), it is fastest to always write the maximum + * number of entries. That gets rid of branches that + * would otherwise be required. + * + * It is not just because of the numerical order that + * our checks go in the order 'presym < 16', 'presym == + * 16', and 'presym == 17'. For typical data this is + * ordered from most frequent to least frequent case. + */ + if presym == 16 + { + if i == 0 + { + return Err(DecodeErrorStatus::CorruptData); + } + + if !self.stream.has(2) + { + return Err(DecodeErrorStatus::InsufficientData); + } + + // repeat previous length three to 6 times + rep_val = lens[i - 1]; + rep_count = 3 + self.stream.get_bits(2); + lens[i..i + 6].fill(rep_val); + i += rep_count as usize; + } + else if presym == 17 + { + if !self.stream.has(3) + { + return Err(DecodeErrorStatus::InsufficientData); + } + /* Repeat zero 3 - 10 times. */ + rep_count = 3 + self.stream.get_bits(3); + lens[i..i + 10].fill(0); + i += rep_count as usize; + } + else + { + if !self.stream.has(7) + { + return Err(DecodeErrorStatus::InsufficientData); + } + // repeat zero 11-138 times. + rep_count = 11 + self.stream.get_bits(7); + lens[i..i + rep_count as usize].fill(0); + i += rep_count as usize; + } + + if i >= num_litlen_syms + num_offset_syms + { + break; + } + } + } + else if block_type == DEFLATE_BLOCKTYPE_STATIC + { + if self.static_codes_loaded + { + return Ok(()); + } + + self.static_codes_loaded = true; + + lens[000..144].fill(8); + lens[144..256].fill(9); + lens[256..280].fill(7); + lens[280..288].fill(8); + lens[288..].fill(5); + + num_litlen_syms = 288; + num_offset_syms = 32; + } + // build offset decode table + self.build_decode_table_inner( + &lens[num_litlen_syms..], + &OFFSET_DECODE_RESULTS, + &mut offset_decode_table, + OFFSET_TABLEBITS, + num_offset_syms, + DEFLATE_MAX_OFFSET_CODEWORD_LENGTH + )?; + + self.build_decode_table_inner( + &lens, + &LITLEN_DECODE_RESULTS, + &mut litlen_decode_table, + LITLEN_TABLE_BITS, + num_litlen_syms, + DEFLATE_MAX_LITLEN_CODEWORD_LENGTH + )?; + + self.deflate_header_tables.offset_decode_table = offset_decode_table; + self.deflate_header_tables.litlen_decode_table = litlen_decode_table; + + Ok(()) + } + /// Build the decode table for the precode + #[allow(clippy::needless_range_loop)] + fn build_decode_table_inner( + &mut self, lens: &[u8], decode_results: &[u32], decode_table: &mut [u32], + table_bits: usize, num_syms: usize, mut max_codeword_len: usize + ) -> Result<(), DecodeErrorStatus> + { + const BITS: u32 = usize::BITS - 1; + + let mut len_counts: [u32; DEFLATE_MAX_CODEWORD_LENGTH + 1] = + [0; DEFLATE_MAX_CODEWORD_LENGTH + 1]; + let mut offsets: [u32; DEFLATE_MAX_CODEWORD_LENGTH + 1] = + [0; DEFLATE_MAX_CODEWORD_LENGTH + 1]; + let mut sorted_syms: [u16; DEFLATE_MAX_NUM_SYMS] = [0; DEFLATE_MAX_NUM_SYMS]; + + let mut i; + + // count how many codewords have each length, including 0. + for sym in 0..num_syms + { + len_counts[usize::from(lens[sym])] += 1; + } + + /* + * Determine the actual maximum codeword length that was used, and + * decrease table_bits to it if allowed. + */ + while max_codeword_len > 1 && len_counts[max_codeword_len] == 0 + { + max_codeword_len -= 1; + } + /* + * Sort the symbols primarily by increasing codeword length and + * A temporary array of length @num_syms. + * secondarily by increasing symbol value; or equivalently by their + * codewords in lexicographic order, since a canonical code is assumed. + * + * For efficiency, also compute 'codespace_used' in the same pass over + * 'len_counts[]' used to build 'offsets[]' for sorting. + */ + offsets[0] = 0; + offsets[1] = len_counts[0]; + + let mut codespace_used = 0_u32; + + for len in 1..max_codeword_len + { + offsets[len + 1] = offsets[len] + len_counts[len]; + codespace_used = (codespace_used << 1) + len_counts[len]; + } + codespace_used = (codespace_used << 1) + len_counts[max_codeword_len]; + + for sym in 0..num_syms + { + let pos = usize::from(lens[sym]); + sorted_syms[offsets[pos] as usize] = sym as u16; + offsets[pos] += 1; + } + i = (offsets[0]) as usize; + + /* + * Check whether the lengths form a complete code (exactly fills the + * codespace), an incomplete code (doesn't fill the codespace), or an + * overfull code (overflows the codespace). A codeword of length 'n' + * uses proportion '1/(2^n)' of the codespace. An overfull code is + * nonsensical, so is considered invalid. An incomplete code is + * considered valid only in two specific cases; see below. + */ + + // Overfull code + if codespace_used > 1 << max_codeword_len + { + return Err(DecodeErrorStatus::Generic("Overflown code")); + } + // incomplete code + if codespace_used < 1 << max_codeword_len + { + let entry = if codespace_used == 0 + { + /* + * An empty code is allowed. This can happen for the + * offset code in DEFLATE, since a dynamic Huffman block + * need not contain any matches. + */ + + /* sym=0, len=1 (arbitrary) */ + make_decode_table_entry(decode_results, 0, 1) + } + else + { + /* + * Allow codes with a single used symbol, with codeword + * length 1. The DEFLATE RFC is unclear regarding this + * case. What zlib's decompressor does is permit this + * for the litlen and offset codes and assume the + * codeword is '0' rather than '1'. We do the same + * except we allow this for precodes too, since there's + * no convincing reason to treat the codes differently. + * We also assign both codewords '0' and '1' to the + * symbol to avoid having to handle '1' specially. + */ + if codespace_used != 1 << (max_codeword_len - 1) || len_counts[1] != 1 + { + return Err(DecodeErrorStatus::Generic( + "Cannot work with empty pre-code table" + )); + } + make_decode_table_entry(decode_results, usize::from(sorted_syms[i]), 1) + }; + /* + * Note: the decode table still must be fully initialized, in + * case the stream is malformed and contains bits from the part + * of the codespace the incomplete code doesn't use. + */ + decode_table.fill(entry); + return Ok(()); + } + + /* + * The lengths form a complete code. Now, enumerate the codewords in + * lexicographic order and fill the decode table entries for each one. + * + * First, process all codewords with len <= table_bits. Each one gets + * '2^(table_bits-len)' direct entries in the table. + * + * Since DEFLATE uses bit-reversed codewords, these entries aren't + * consecutive but rather are spaced '2^len' entries apart. This makes + * filling them naively somewhat awkward and inefficient, since strided + * stores are less cache-friendly and preclude the use of word or + * vector-at-a-time stores to fill multiple entries per instruction. + * + * To optimize this, we incrementally double the table size. When + * processing codewords with length 'len', the table is treated as + * having only '2^len' entries, so each codeword uses just one entry. + * Then, each time 'len' is incremented, the table size is doubled and + * the first half is copied to the second half. This significantly + * improves performance over naively doing strided stores. + * + * Note that some entries copied for each table doubling may not have + * been initialized yet, but it doesn't matter since they're guaranteed + * to be initialized later (because the Huffman code is complete). + */ + let mut codeword = 0; + let mut len = 1; + let mut count = len_counts[1]; + + while count == 0 + { + len += 1; + + if len >= len_counts.len() + { + break; + } + count = len_counts[len]; + } + + let mut curr_table_end = 1 << len; + + while len <= table_bits + { + // Process all count codewords with length len + loop + { + let entry = make_decode_table_entry( + decode_results, + usize::from(sorted_syms[i]), + len as u32 + ); + i += 1; + // fill first entry for current codeword + decode_table[codeword] = entry; + + if codeword == curr_table_end - 1 + { + // last codeword (all 1's) + for _ in len..table_bits + { + decode_table.copy_within(0..curr_table_end, curr_table_end); + + curr_table_end <<= 1; + } + return Ok(()); + } + /* + * To advance to the lexicographically next codeword in + * the canonical code, the codeword must be incremented, + * then 0's must be appended to the codeword as needed + * to match the next codeword's length. + * + * Since the codeword is bit-reversed, appending 0's is + * a no-op. However, incrementing it is nontrivial. To + * do so efficiently, use the 'bsr' instruction to find + * the last (highest order) 0 bit in the codeword, set + * it, and clear any later (higher order) 1 bits. But + * 'bsr' actually finds the highest order 1 bit, so to + * use it first flip all bits in the codeword by XOR' ing + * it with (1U << len) - 1 == cur_table_end - 1. + */ + + let adv = BITS - (codeword ^ (curr_table_end - 1)).leading_zeros(); + let bit = 1 << adv; + + codeword &= bit - 1; + codeword |= bit; + count -= 1; + + if count == 0 + { + break; + } + } + // advance to the next codeword length + loop + { + len += 1; + + if len <= table_bits + { + // dest is decode_table[curr_table_end] + // source is decode_table(start of table); + // size is curr_table; + + decode_table.copy_within(0..curr_table_end, curr_table_end); + + //decode_table.copy_within(range, curr_table_end); + curr_table_end <<= 1; + } + count = len_counts[len]; + + if count != 0 + { + break; + } + } + } + // process codewords with len > table_bits. + // Require sub-tables + curr_table_end = 1 << table_bits; + + let mut subtable_prefix = usize::MAX; + let mut subtable_start = 0; + let mut subtable_bits; + + loop + { + /* + * Start a new sub-table if the first 'table_bits' bits of the + * codeword don't match the prefix of the current subtable. + */ + if codeword & ((1_usize << table_bits) - 1) != subtable_prefix + { + subtable_prefix = codeword & ((1 << table_bits) - 1); + subtable_start = curr_table_end; + + /* + * Calculate the subtable length. If the codeword has + * length 'table_bits + n', then the subtable needs + * '2^n' entries. But it may need more; if fewer than + * '2^n' codewords of length 'table_bits + n' remain, + * then the length will need to be incremented to bring + * in longer codewords until the subtable can be + * completely filled. Note that because the Huffman + * code is complete, it will always be possible to fill + * the sub-table eventually. + */ + subtable_bits = len - table_bits; + codespace_used = count; + + while codespace_used < (1 << subtable_bits) + { + subtable_bits += 1; + + if subtable_bits + table_bits > 15 + { + return Err(DecodeErrorStatus::CorruptData); + } + + codespace_used = (codespace_used << 1) + len_counts[table_bits + subtable_bits]; + } + + /* + * Create the entry that points from the main table to + * the subtable. + */ + decode_table[subtable_prefix] = (subtable_start as u32) << 16 + | HUFFDEC_EXCEPTIONAL + | HUFFDEC_SUITABLE_POINTER + | (subtable_bits as u32) << 8 + | table_bits as u32; + + curr_table_end = subtable_start + (1 << subtable_bits); + } + + /* Fill the sub-table entries for the current codeword. */ + + let stride = 1 << (len - table_bits); + + let mut j = subtable_start + (codeword >> table_bits); + + let entry = make_decode_table_entry( + decode_results, + sorted_syms[i] as usize, + (len - table_bits) as u32 + ); + i += 1; + + while j < curr_table_end + { + decode_table[j] = entry; + j += stride; + } + //advance to the next codeword + if codeword == (1 << len) - 1 + { + // last codeword + return Ok(()); + } + + let adv = BITS - (codeword ^ ((1 << len) - 1)).leading_zeros(); + let bit = 1 << adv; + + codeword &= bit - 1; + codeword |= bit; + count -= 1; + + while count == 0 + { + len += 1; + count = len_counts[len]; + } + } + } +} + +const RESIZE_BY: usize = 1024 * 4; // 4 kb + +/// Resize vector if its current space wont +/// be able to store a new byte and then push an element to that new space +#[inline(always)] +fn resize_and_push(buf: &mut Vec<u8>, position: usize, elm: u8) +{ + if buf.len() <= position + { + let new_len = buf.len() + RESIZE_BY; + buf.resize(new_len, 0); + } + buf[position] = elm; +} |