/*
* 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)
}
}