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 | |