1use crate::bitstream::LsbWriter;
2use crate::deflate_state::LengthBuffers;
3use crate::huffman_table::{
4 create_codes_in_place, num_extra_bits_for_distance_code, num_extra_bits_for_length_code,
5 HuffmanTable, FIXED_CODE_LENGTHS, LENGTH_BITS_START, MAX_CODE_LENGTH, NUM_DISTANCE_CODES,
6 NUM_LITERALS_AND_LENGTHS,
7};
8use crate::length_encode::{
9 encode_lengths_m, huffman_lengths_from_frequency_m, EncodedLength, COPY_PREVIOUS,
10 REPEAT_ZERO_3_BITS, REPEAT_ZERO_7_BITS,
11};
12use crate::output_writer::FrequencyType;
13use crate::stored_block::MAX_STORED_BLOCK_LENGTH;
14
15use std::cmp;
16
17pub const MIN_NUM_LITERALS_AND_LENGTHS: usize = 257;
19pub const MIN_NUM_DISTANCES: usize = 1;
21
22const NUM_HUFFMAN_LENGTHS: usize = 19;
23
24const HUFFMAN_LENGTH_ORDER: [u8; NUM_HUFFMAN_LENGTHS] = [
28 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
29];
30
31const HLIT_BITS: u8 = 5;
33const HDIST_BITS: u8 = 5;
34const HCLEN_BITS: u8 = 4;
35
36const MAX_HUFFMAN_CODE_LENGTH: usize = 7;
38
39const STORED_BLOCK_HEADER_LENGTH: u64 = 4;
41const BLOCK_MARKER_LENGTH: u8 = 3;
42
43pub fn remove_trailing_zeroes<T: From<u8> + PartialEq>(input: &[T], min_length: usize) -> &[T] {
45 let num_zeroes = input.iter().rev().take_while(|&a| *a == T::from(0)).count();
46 &input[0..cmp::max(input.len() - num_zeroes, min_length)]
47}
48
49fn extra_bits_for_huffman_length_code(code: u8) -> u8 {
51 match code {
52 16..=17 => 3,
53 18 => 7,
54 _ => 0,
55 }
56}
57
58fn calculate_huffman_length(frequencies: &[FrequencyType], code_lengths: &[u8]) -> u64 {
60 frequencies
61 .iter()
62 .zip(code_lengths)
63 .enumerate()
64 .fold(0, |acc, (n, (&f, &l))| {
65 acc + (u64::from(f)
66 * (u64::from(l) + u64::from(extra_bits_for_huffman_length_code(n as u8))))
67 })
68}
69
70fn calculate_block_length<F>(
77 frequencies: &[FrequencyType],
78 dyn_code_lengths: &[u8],
79 get_num_extra_bits: &F,
80) -> (u64, u64)
81where
82 F: Fn(usize) -> u64,
83{
84 let mut d_ll_length = 0u64;
86 let mut s_ll_length = 0u64;
88
89 let iter = frequencies
90 .iter()
91 .zip(dyn_code_lengths.iter().zip(FIXED_CODE_LENGTHS.iter()))
92 .enumerate();
93
94 for (c, (&f, (&l, &fl))) in iter {
97 let f = u64::from(f);
99 let extra_bits_for_code = get_num_extra_bits(c);
101
102 d_ll_length += f * (u64::from(l) + extra_bits_for_code);
103 s_ll_length += f * (u64::from(fl) + extra_bits_for_code);
104 }
105
106 (d_ll_length, s_ll_length)
107}
108
109fn stored_padding(pending_bits: u8) -> u64 {
114 assert!(pending_bits <= 8);
115 let free_space = 8 - pending_bits;
116 if free_space >= BLOCK_MARKER_LENGTH {
117 free_space - BLOCK_MARKER_LENGTH
119 } else {
120 8 - (BLOCK_MARKER_LENGTH - free_space)
122 }
123 .into()
124}
125
126fn stored_length(input_bytes: u64) -> u64 {
133 let num_blocks = (input_bytes
136 .checked_sub(1)
137 .expect("Underflow calculating stored block length!")
138 / MAX_STORED_BLOCK_LENGTH as u64)
139 + 1;
140 (input_bytes + (STORED_BLOCK_HEADER_LENGTH as u64 * num_blocks) + (num_blocks - 1)) * 8
143}
144
145pub enum BlockType {
146 Stored,
147 Fixed,
148 Dynamic(DynamicBlockHeader),
149}
150
151pub struct DynamicBlockHeader {
156 pub huffman_table_lengths: Vec<u8>,
158 pub used_hclens: usize,
161}
162
163pub fn gen_huffman_lengths(
168 l_freqs: &[FrequencyType],
169 d_freqs: &[FrequencyType],
170 num_input_bytes: u64,
171 pending_bits: u8,
172 l_lengths: &mut [u8; 288],
173 d_lengths: &mut [u8; 32],
174 length_buffers: &mut LengthBuffers,
175) -> BlockType {
176 if num_input_bytes <= 4 {
180 return BlockType::Fixed;
181 };
182
183 let l_freqs = remove_trailing_zeroes(l_freqs, MIN_NUM_LITERALS_AND_LENGTHS);
184 let d_freqs = remove_trailing_zeroes(d_freqs, MIN_NUM_DISTANCES);
185
186 huffman_lengths_from_frequency_m(
195 l_freqs,
196 MAX_CODE_LENGTH,
197 &mut length_buffers.leaf_buf,
198 l_lengths,
199 );
200 huffman_lengths_from_frequency_m(
201 d_freqs,
202 MAX_CODE_LENGTH,
203 &mut length_buffers.leaf_buf,
204 d_lengths,
205 );
206
207 let used_lengths = l_freqs.len();
208 let used_distances = d_freqs.len();
209
210 let mut freqs = [0u16; 19];
212 encode_lengths_m(
213 l_lengths[..used_lengths]
214 .iter()
215 .chain(&d_lengths[..used_distances]),
216 &mut length_buffers.length_buf,
217 &mut freqs,
218 );
219
220 let mut huffman_table_lengths = vec![0; freqs.len()];
222 huffman_lengths_from_frequency_m(
223 &freqs,
224 MAX_HUFFMAN_CODE_LENGTH,
225 &mut length_buffers.leaf_buf,
226 huffman_table_lengths.as_mut_slice(),
227 );
228
229 let used_hclens = HUFFMAN_LENGTH_ORDER.len()
231 - HUFFMAN_LENGTH_ORDER
232 .iter()
233 .rev()
234 .take_while(|&&n| huffman_table_lengths[n as usize] == 0)
235 .count();
236
237 debug_assert!(used_hclens >= 4);
239
240 let (d_ll_length, s_ll_length) = calculate_block_length(l_freqs, l_lengths, &|c| {
245 num_extra_bits_for_length_code(c.saturating_sub(LENGTH_BITS_START as usize) as u8).into()
246 });
247
248 let (d_dist_length, s_dist_length) = calculate_block_length(d_freqs, d_lengths, &|c| {
250 num_extra_bits_for_distance_code(c as u8).into()
251 });
252
253 let huff_table_length = calculate_huffman_length(&freqs, &huffman_table_lengths);
255
256 let dynamic_length = d_ll_length
258 + d_dist_length
259 + huff_table_length
260 + (used_hclens as u64 * 3)
261 + u64::from(HLIT_BITS)
262 + u64::from(HDIST_BITS)
263 + u64::from(HCLEN_BITS);
264
265 let static_length = s_ll_length + s_dist_length;
267
268 let stored_length = stored_length(num_input_bytes) + stored_padding(pending_bits % 8);
270
271 let used_length = cmp::min(cmp::min(dynamic_length, static_length), stored_length);
272
273 if used_length == static_length {
278 BlockType::Fixed
279 } else if used_length == stored_length {
280 BlockType::Stored
281 } else {
282 BlockType::Dynamic(DynamicBlockHeader {
283 huffman_table_lengths,
284 used_hclens,
285 })
286 }
287}
288
289pub fn write_huffman_lengths(
291 header: &DynamicBlockHeader,
292 huffman_table: &HuffmanTable,
293 encoded_lengths: &[EncodedLength],
294 writer: &mut LsbWriter,
295) {
296 let (literal_len_lengths, distance_lengths) = huffman_table.get_lengths();
298 let literal_len_lengths =
299 remove_trailing_zeroes(literal_len_lengths, MIN_NUM_LITERALS_AND_LENGTHS);
300 let distance_lengths = remove_trailing_zeroes(distance_lengths, MIN_NUM_DISTANCES);
301 let huffman_table_lengths = &header.huffman_table_lengths;
302 let used_hclens = header.used_hclens;
303
304 assert!(literal_len_lengths.len() <= NUM_LITERALS_AND_LENGTHS);
305 assert!(literal_len_lengths.len() >= MIN_NUM_LITERALS_AND_LENGTHS);
306 assert!(distance_lengths.len() <= NUM_DISTANCE_CODES);
307 assert!(distance_lengths.len() >= MIN_NUM_DISTANCES);
308
309 let hlit = (literal_len_lengths.len() - MIN_NUM_LITERALS_AND_LENGTHS) as u16;
311 writer.write_bits(hlit, HLIT_BITS);
312 let hdist = (distance_lengths.len() - MIN_NUM_DISTANCES) as u16;
314 writer.write_bits(hdist, HDIST_BITS);
315
316 let hclen = used_hclens.saturating_sub(4);
318
319 writer.write_bits(hclen as u16, HCLEN_BITS);
323
324 for n in &HUFFMAN_LENGTH_ORDER[..used_hclens] {
327 writer.write_bits(u16::from(huffman_table_lengths[usize::from(*n)]), 3);
328 }
329
330 let mut codes = [0u16; NUM_HUFFMAN_LENGTHS];
332 create_codes_in_place(&mut codes[..], huffman_table_lengths);
333
334 for v in encoded_lengths {
336 match *v {
337 EncodedLength::Length(n) => {
338 let (c, l) = (codes[usize::from(n)], huffman_table_lengths[usize::from(n)]);
339 writer.write_bits(c, l);
340 }
341 EncodedLength::CopyPrevious(n) => {
342 let (c, l) = (codes[COPY_PREVIOUS], huffman_table_lengths[COPY_PREVIOUS]);
343 writer.write_bits(c, l);
344 debug_assert!(n >= 3);
345 debug_assert!(n <= 6);
346 writer.write_bits((n - 3).into(), 2);
347 }
348 EncodedLength::RepeatZero3Bits(n) => {
349 let (c, l) = (
350 codes[REPEAT_ZERO_3_BITS],
351 huffman_table_lengths[REPEAT_ZERO_3_BITS],
352 );
353 writer.write_bits(c, l);
354 debug_assert!(n >= 3);
355 writer.write_bits((n - 3).into(), 3);
356 }
357 EncodedLength::RepeatZero7Bits(n) => {
358 let (c, l) = (
359 codes[REPEAT_ZERO_7_BITS],
360 huffman_table_lengths[REPEAT_ZERO_7_BITS],
361 );
362 writer.write_bits(c, l);
363 debug_assert!(n >= 11);
364 debug_assert!(n <= 138);
365 writer.write_bits((n - 11).into(), 7);
366 }
367 }
368 }
369}
370
371#[cfg(test)]
372mod test {
373 use super::stored_padding;
374 #[test]
375 fn padding() {
376 assert_eq!(stored_padding(0), 5);
377 assert_eq!(stored_padding(1), 4);
378 assert_eq!(stored_padding(2), 3);
379 assert_eq!(stored_padding(3), 2);
380 assert_eq!(stored_padding(4), 1);
381 assert_eq!(stored_padding(5), 0);
382 assert_eq!(stored_padding(6), 7);
383 assert_eq!(stored_padding(7), 6);
384 }
385}