| 1 | /* |
| 2 | * Copyright (c) 2023. |
| 3 | * |
| 4 | * This software is free software; You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license |
| 5 | */ |
| 6 | |
| 7 | use alloc::vec; |
| 8 | use alloc::vec::Vec; |
| 9 | |
| 10 | use crate::constants::DEFLATE_BLOCKTYPE_UNCOMPRESSED; |
| 11 | |
| 12 | mod fast_match_finder; |
| 13 | |
| 14 | const _SEQ_LENGTH_SHIFT: u32 = 23; |
| 15 | |
| 16 | const _SEQ_LITRUNLEN_MASK: u32 = (1_u32 << _SEQ_LENGTH_SHIFT) - 1; |
| 17 | |
| 18 | pub(crate) struct _Sequence |
| 19 | { |
| 20 | /* |
| 21 | * Bits 0..22: the number of literals in this run. This may be 0 and |
| 22 | * can be at most MAX_BLOCK_LENGTH. The literals are not stored |
| 23 | * explicitly in this structure; instead, they are read directly from |
| 24 | * the uncompressed data. |
| 25 | * |
| 26 | * Bits 23..31: the length of the match which follows the literals, or 0 |
| 27 | * if this literal run was the last in the block, so there is no match |
| 28 | * which follows it. |
| 29 | */ |
| 30 | litrunlen_and_length: u32 |
| 31 | } |
| 32 | |
| 33 | #[derive (Debug, Copy, Clone)] |
| 34 | pub enum DeflateEncodingStrategy |
| 35 | { |
| 36 | NoCompression |
| 37 | } |
| 38 | |
| 39 | impl DeflateEncodingStrategy |
| 40 | { |
| 41 | #[allow (dead_code)] |
| 42 | fn to_level(self) -> u8 |
| 43 | { |
| 44 | match self |
| 45 | { |
| 46 | Self::NoCompression => 0 |
| 47 | } |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | pub struct DeflateEncodingOptions |
| 52 | { |
| 53 | strategy: DeflateEncodingStrategy |
| 54 | } |
| 55 | |
| 56 | impl Default for DeflateEncodingOptions |
| 57 | { |
| 58 | fn default() -> Self |
| 59 | { |
| 60 | DeflateEncodingOptions { |
| 61 | strategy: DeflateEncodingStrategy::NoCompression |
| 62 | } |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | /// A simple Deflate Encoder. |
| 67 | /// |
| 68 | /// Not yet complete |
| 69 | pub struct DeflateEncoder<'a> |
| 70 | { |
| 71 | data: &'a [u8], |
| 72 | options: DeflateEncodingOptions, |
| 73 | output_position: usize, |
| 74 | input_position: usize, |
| 75 | output: Vec<u8> |
| 76 | } |
| 77 | |
| 78 | impl<'a> DeflateEncoder<'a> |
| 79 | { |
| 80 | /// Create a new deflate encoder. |
| 81 | /// |
| 82 | /// The |
| 83 | pub fn new(data: &'a [u8]) -> DeflateEncoder<'a> |
| 84 | { |
| 85 | DeflateEncoder::new_with_options(data, DeflateEncodingOptions::default()) |
| 86 | } |
| 87 | pub fn new_with_options(data: &'a [u8], options: DeflateEncodingOptions) -> DeflateEncoder<'a> |
| 88 | { |
| 89 | let length = data.len() + 1024; |
| 90 | let out_array = vec![0; length]; |
| 91 | |
| 92 | DeflateEncoder { |
| 93 | data, |
| 94 | options, |
| 95 | output_position: 0, |
| 96 | input_position: 0, |
| 97 | output: out_array |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | #[cfg (feature = "zlib" )] |
| 102 | fn write_zlib_header(&mut self) |
| 103 | { |
| 104 | const ZLIB_CM_DEFLATE: u16 = 8; |
| 105 | const ZLIB_CINFO_32K_WINDOW: u16 = 7; |
| 106 | |
| 107 | let level_hint = self.options.strategy.to_level(); |
| 108 | |
| 109 | let mut hdr = (ZLIB_CM_DEFLATE << 8) | (ZLIB_CINFO_32K_WINDOW << 12); |
| 110 | |
| 111 | hdr |= u16::from(level_hint) << 6; |
| 112 | hdr |= 31 - (hdr % 31); |
| 113 | |
| 114 | self.output[self.output_position..self.output_position + 2] |
| 115 | .copy_from_slice(&hdr.to_be_bytes()); |
| 116 | } |
| 117 | /// Encode a deflate data block with no compression |
| 118 | /// |
| 119 | /// # Argument |
| 120 | /// - `bytes`: number of bytes to compress from input as non-compressed |
| 121 | /// bytes |
| 122 | fn encode_no_compression(&mut self, bytes: usize) |
| 123 | { |
| 124 | let final_position = self.input_position + bytes; |
| 125 | |
| 126 | /* |
| 127 | * If the input is zero-length, we still must output a block in order |
| 128 | * for the output to be a valid DEFLATE stream. Handle this case |
| 129 | * specially to avoid potentially passing NULL to memcpy() below. |
| 130 | */ |
| 131 | if self.data.is_empty() |
| 132 | { |
| 133 | /* BFINAL and BTYPE */ |
| 134 | self.output[self.output_position] = (1 | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8; |
| 135 | self.output_position += 1; |
| 136 | /* LEN and NLEN */ |
| 137 | let num: u32 = 0xFFFF0000; |
| 138 | self.output[self.output_position..self.output_position + 4] |
| 139 | .copy_from_slice(&num.to_le_bytes()); |
| 140 | self.output_position += 4; |
| 141 | return; |
| 142 | } |
| 143 | loop |
| 144 | { |
| 145 | let mut bfinal = 0; |
| 146 | let mut len = usize::from(u16::MAX); |
| 147 | |
| 148 | if final_position - self.input_position <= usize::from(u16::MAX) |
| 149 | { |
| 150 | bfinal = 1; |
| 151 | len = final_position - self.input_position; |
| 152 | } |
| 153 | /* |
| 154 | * Output BFINAL and BTYPE. The stream is already byte-aligned |
| 155 | * here, so this step always requires outputting exactly 1 byte. |
| 156 | */ |
| 157 | self.output[self.output_position] = |
| 158 | (bfinal | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8; |
| 159 | |
| 160 | self.output_position += 1; |
| 161 | // output len and nlen |
| 162 | let len_u16 = len as u16; |
| 163 | |
| 164 | self.output[self.output_position..self.output_position + 2] |
| 165 | .copy_from_slice(&len_u16.to_le_bytes()); |
| 166 | self.output_position += 2; |
| 167 | |
| 168 | self.output[self.output_position..self.output_position + 2] |
| 169 | .copy_from_slice(&(!len_u16).to_le_bytes()); |
| 170 | self.output_position += 2; |
| 171 | |
| 172 | // copy from input to output |
| 173 | self.output[self.output_position..self.output_position + len] |
| 174 | .copy_from_slice(&self.data[self.input_position..self.input_position + len]); |
| 175 | self.output_position += len; |
| 176 | self.input_position += len; |
| 177 | |
| 178 | if self.input_position == final_position |
| 179 | { |
| 180 | break; |
| 181 | } |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | /// Encode a deflate stream |
| 186 | pub fn encode_deflate(&mut self) |
| 187 | { |
| 188 | match self.options.strategy |
| 189 | { |
| 190 | DeflateEncodingStrategy::NoCompression => |
| 191 | { |
| 192 | self.encode_no_compression(self.data.len()); |
| 193 | } |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | #[cfg (feature = "zlib" )] |
| 198 | pub fn encode_zlib(&mut self) -> Vec<u8> |
| 199 | { |
| 200 | let extra = 40 * ((self.data.len() + 41) / 40); |
| 201 | self.output = vec![0_u8; self.data.len() + extra]; |
| 202 | self.write_zlib_header(); |
| 203 | self.output_position = 2; |
| 204 | |
| 205 | self.encode_deflate(); |
| 206 | |
| 207 | // add adler hash |
| 208 | let hash = crate::utils::calc_adler_hash(self.data); |
| 209 | self.output[self.output_position..self.output_position + 4] |
| 210 | .copy_from_slice(&hash.to_be_bytes()); |
| 211 | self.output_position += 4; |
| 212 | |
| 213 | self.output.truncate(self.output_position); |
| 214 | |
| 215 | core::mem::take(&mut self.output) |
| 216 | } |
| 217 | } |
| 218 | |