diff options
Diffstat (limited to 'vendor/zune-inflate/src/encoder.rs')
-rw-r--r-- | vendor/zune-inflate/src/encoder.rs | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/vendor/zune-inflate/src/encoder.rs b/vendor/zune-inflate/src/encoder.rs new file mode 100644 index 0000000..f53f599 --- /dev/null +++ b/vendor/zune-inflate/src/encoder.rs @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2023. + * + * This software is free software; You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license + */ + +use alloc::vec; +use alloc::vec::Vec; + +use crate::constants::DEFLATE_BLOCKTYPE_UNCOMPRESSED; + +mod fast_match_finder; + +const _SEQ_LENGTH_SHIFT: u32 = 23; + +const _SEQ_LITRUNLEN_MASK: u32 = (1_u32 << _SEQ_LENGTH_SHIFT) - 1; + +pub(crate) struct _Sequence +{ + /* + * Bits 0..22: the number of literals in this run. This may be 0 and + * can be at most MAX_BLOCK_LENGTH. The literals are not stored + * explicitly in this structure; instead, they are read directly from + * the uncompressed data. + * + * Bits 23..31: the length of the match which follows the literals, or 0 + * if this literal run was the last in the block, so there is no match + * which follows it. + */ + litrunlen_and_length: u32 +} + +#[derive(Debug, Copy, Clone)] +pub enum DeflateEncodingStrategy +{ + NoCompression +} + +impl DeflateEncodingStrategy +{ + #[allow(dead_code)] + fn to_level(self) -> u8 + { + match self + { + Self::NoCompression => 0 + } + } +} + +pub struct DeflateEncodingOptions +{ + strategy: DeflateEncodingStrategy +} + +impl Default for DeflateEncodingOptions +{ + fn default() -> Self + { + DeflateEncodingOptions { + strategy: DeflateEncodingStrategy::NoCompression + } + } +} + +/// A simple Deflate Encoder. +/// +/// Not yet complete +pub struct DeflateEncoder<'a> +{ + data: &'a [u8], + options: DeflateEncodingOptions, + output_position: usize, + input_position: usize, + output: Vec<u8> +} + +impl<'a> DeflateEncoder<'a> +{ + /// Create a new deflate encoder. + /// + /// The + pub fn new(data: &'a [u8]) -> DeflateEncoder<'a> + { + DeflateEncoder::new_with_options(data, DeflateEncodingOptions::default()) + } + pub fn new_with_options(data: &'a [u8], options: DeflateEncodingOptions) -> DeflateEncoder<'a> + { + let length = data.len() + 1024; + let out_array = vec![0; length]; + + DeflateEncoder { + data, + options, + output_position: 0, + input_position: 0, + output: out_array + } + } + + #[cfg(feature = "zlib")] + fn write_zlib_header(&mut self) + { + const ZLIB_CM_DEFLATE: u16 = 8; + const ZLIB_CINFO_32K_WINDOW: u16 = 7; + + let level_hint = self.options.strategy.to_level(); + + let mut hdr = (ZLIB_CM_DEFLATE << 8) | (ZLIB_CINFO_32K_WINDOW << 12); + + hdr |= u16::from(level_hint) << 6; + hdr |= 31 - (hdr % 31); + + self.output[self.output_position..self.output_position + 2] + .copy_from_slice(&hdr.to_be_bytes()); + } + /// Encode a deflate data block with no compression + /// + /// # Argument + /// - `bytes`: number of bytes to compress from input as non-compressed + /// bytes + fn encode_no_compression(&mut self, bytes: usize) + { + let final_position = self.input_position + bytes; + + /* + * If the input is zero-length, we still must output a block in order + * for the output to be a valid DEFLATE stream. Handle this case + * specially to avoid potentially passing NULL to memcpy() below. + */ + if self.data.is_empty() + { + /* BFINAL and BTYPE */ + self.output[self.output_position] = (1 | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8; + self.output_position += 1; + /* LEN and NLEN */ + let num: u32 = 0xFFFF0000; + self.output[self.output_position..self.output_position + 4] + .copy_from_slice(&num.to_le_bytes()); + self.output_position += 4; + return; + } + loop + { + let mut bfinal = 0; + let mut len = usize::from(u16::MAX); + + if final_position - self.input_position <= usize::from(u16::MAX) + { + bfinal = 1; + len = final_position - self.input_position; + } + /* + * Output BFINAL and BTYPE. The stream is already byte-aligned + * here, so this step always requires outputting exactly 1 byte. + */ + self.output[self.output_position] = + (bfinal | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8; + + self.output_position += 1; + // output len and nlen + let len_u16 = len as u16; + + self.output[self.output_position..self.output_position + 2] + .copy_from_slice(&len_u16.to_le_bytes()); + self.output_position += 2; + + self.output[self.output_position..self.output_position + 2] + .copy_from_slice(&(!len_u16).to_le_bytes()); + self.output_position += 2; + + // copy from input to output + self.output[self.output_position..self.output_position + len] + .copy_from_slice(&self.data[self.input_position..self.input_position + len]); + self.output_position += len; + self.input_position += len; + + if self.input_position == final_position + { + break; + } + } + } + + /// Encode a deflate stream + pub fn encode_deflate(&mut self) + { + match self.options.strategy + { + DeflateEncodingStrategy::NoCompression => + { + self.encode_no_compression(self.data.len()); + } + } + } + + #[cfg(feature = "zlib")] + pub fn encode_zlib(&mut self) -> Vec<u8> + { + let extra = 40 * ((self.data.len() + 41) / 40); + self.output = vec![0_u8; self.data.len() + extra]; + self.write_zlib_header(); + self.output_position = 2; + + self.encode_deflate(); + + // add adler hash + let hash = crate::utils::calc_adler_hash(self.data); + self.output[self.output_position..self.output_position + 4] + .copy_from_slice(&hash.to_be_bytes()); + self.output_position += 4; + + self.output.truncate(self.output_position); + + core::mem::take(&mut self.output) + } +} |