Skip to main content

simd_brotli/enc/
brotli_bit_stream.rs

1#![allow(unknown_lints)]
2#![allow(unused_macros)]
3
4use core::cmp::{max, min};
5#[cfg(feature = "std")]
6use std::io::Write;
7
8use super::super::alloc;
9use super::super::alloc::{Allocator, SliceWrapper, SliceWrapperMut};
10use super::super::dictionary::{
11    kBrotliDictionary, kBrotliDictionaryOffsetsByLength, kBrotliDictionarySizeBitsByLength,
12};
13use super::super::transform::TransformDictionaryWord;
14use super::block_split::BlockSplit;
15use super::combined_alloc::BrotliAlloc;
16use super::command::{Command, GetCopyLengthCode, GetInsertLengthCode};
17use super::constants::{
18    BROTLI_CONTEXT_LUT, BROTLI_NUM_BLOCK_LEN_SYMBOLS, BROTLI_NUM_COMMAND_SYMBOLS,
19    BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS, BROTLI_NUM_LITERAL_SYMBOLS, kCodeLengthBits,
20    kCodeLengthDepth, kCopyBase, kCopyExtra, kInsBase, kInsExtra, kNonZeroRepsBits,
21    kNonZeroRepsDepth, kSigned3BitContextLookup, kStaticCommandCodeBits, kStaticCommandCodeDepth,
22    kStaticDistanceCodeBits, kStaticDistanceCodeDepth, kUTF8ContextLookup, kZeroRepsBits,
23    kZeroRepsDepth,
24};
25use super::context_map_entropy::{ContextMapEntropy, SpeedAndMax, speed_to_tuple};
26use super::entropy_encode::{
27    BrotliConvertBitDepthsToSymbols, BrotliCreateHuffmanTree, BrotliSetDepth,
28    BrotliWriteHuffmanTree, HuffmanComparator, HuffmanTree, SortHuffmanTreeItems,
29};
30use super::histogram::{
31    ContextType, HistogramAddItem, HistogramCommand, HistogramDistance, HistogramLiteral,
32};
33use super::input_pair::{InputPair, InputReference, InputReferenceMut};
34use super::interface::StaticCommand;
35use super::static_dict::kNumDistanceCacheEntries;
36use super::util::floatX;
37use super::{find_stride, interface, prior_eval, stride_eval};
38use crate::VERSION;
39use crate::enc::backward_references::BrotliEncoderParams;
40use crate::enc::combined_alloc::{alloc_default, alloc_or_default, allocate};
41
42pub struct PrefixCodeRange {
43    pub offset: u32,
44    pub nbits: u32,
45}
46pub const MAX_SIMPLE_DISTANCE_ALPHABET_SIZE: usize = 140;
47
48fn window_size_from_lgwin(lgwin: i32) -> usize {
49    (1 << lgwin) - 16usize
50}
51
52struct CommandQueue<'a, Alloc: BrotliAlloc + 'a> {
53    mb: InputPair<'a>,
54    // TODO: delete unused fields
55    #[allow(dead_code)]
56    mb_byte_offset: usize,
57    mc: &'a mut Alloc,
58    queue: <Alloc as Allocator<StaticCommand>>::AllocatedMemory,
59    pred_mode: interface::PredictionModeContextMap<InputReferenceMut<'a>>,
60    loc: usize,
61    entropy_tally_scratch: find_stride::EntropyTally<Alloc>,
62    best_strides_per_block_type: <Alloc as Allocator<u8>>::AllocatedMemory,
63    entropy_pyramid: find_stride::EntropyPyramid<Alloc>,
64    context_map_entropy: ContextMapEntropy<'a, Alloc>,
65    #[allow(dead_code)]
66    stride_detection_quality: u8,
67    #[allow(dead_code)]
68    high_entropy_detection_quality: u8,
69    block_type_literal: u8,
70    #[allow(dead_code)]
71    best_stride_index: usize,
72    overfull: bool,
73}
74
75impl<'a, Alloc: BrotliAlloc> CommandQueue<'a, Alloc> {
76    fn new(
77        alloc: &'a mut Alloc,
78        num_commands: usize,
79        pred_mode: interface::PredictionModeContextMap<InputReferenceMut<'a>>,
80        mb: InputPair<'a>,
81        stride_detection_quality: u8,
82        high_entropy_detection_quality: u8,
83        context_map_entropy: ContextMapEntropy<'a, Alloc>,
84        best_strides: <Alloc as Allocator<u8>>::AllocatedMemory,
85        entropy_tally_scratch: find_stride::EntropyTally<Alloc>,
86        entropy_pyramid: find_stride::EntropyPyramid<Alloc>,
87    ) -> CommandQueue<'a, Alloc> {
88        // assume no more than 1/16 of the stream is block_types which may chop up literals
89        // also there's the first btypel and a potential wrap around the ring buffer
90        let queue = allocate::<StaticCommand, _>(alloc, num_commands * 17 / 16 + 4);
91        CommandQueue {
92            mc: alloc,
93            queue, // always need a spare command in case the ring buffer splits a literal into two
94            pred_mode,
95            mb,
96            mb_byte_offset: 0,
97            loc: 0,
98            best_strides_per_block_type: best_strides,
99            entropy_tally_scratch,
100            entropy_pyramid,
101            stride_detection_quality,
102            high_entropy_detection_quality,
103            context_map_entropy,
104            block_type_literal: 0,
105            best_stride_index: 0,
106            overfull: false,
107        }
108    }
109    fn full(&self) -> bool {
110        self.loc == self.queue.len()
111    }
112    fn error_if_full(&mut self) {
113        if self.full() {
114            self.overfull = true;
115        }
116    }
117    fn clear(&mut self) {
118        self.loc = 0;
119        self.block_type_literal = 0;
120    }
121    fn free<Cb>(&mut self, callback: &mut Cb) -> Result<(), ()>
122    where
123        Cb: FnMut(
124            &mut interface::PredictionModeContextMap<InputReferenceMut>,
125            &mut [interface::StaticCommand],
126            InputPair,
127            &mut Alloc,
128        ),
129    {
130        callback(
131            &mut self.pred_mode,
132            self.queue.slice_mut().split_at_mut(self.loc).0,
133            self.mb,
134            self.mc,
135        );
136        self.clear();
137        self.entropy_tally_scratch.free(self.mc);
138        self.entropy_pyramid.free(self.mc);
139        self.context_map_entropy.free(self.mc);
140        <Alloc as Allocator<StaticCommand>>::free_cell(self.mc, core::mem::take(&mut self.queue));
141        <Alloc as Allocator<u8>>::free_cell(
142            self.mc,
143            core::mem::take(&mut self.best_strides_per_block_type),
144        );
145        if self.overfull {
146            return Err(());
147        }
148        Ok(())
149    }
150}
151
152impl<'a, Alloc: BrotliAlloc> interface::CommandProcessor<'a> for CommandQueue<'a, Alloc> {
153    fn push(&mut self, val: interface::Command<InputReference<'a>>) {
154        if self.full() {
155            let mut tmp = allocate::<StaticCommand, _>(self.mc, self.queue.slice().len() * 2);
156            tmp.slice_mut()
157                .split_at_mut(self.queue.slice().len())
158                .0
159                .clone_from_slice(self.queue.slice());
160            <Alloc as Allocator<StaticCommand>>::free_cell(
161                self.mc,
162                core::mem::replace(&mut self.queue, tmp),
163            );
164        }
165        if !self.full() {
166            self.queue.slice_mut()[self.loc] = val.freeze();
167            self.loc += 1;
168        } else {
169            self.error_if_full();
170        }
171    }
172    fn push_block_switch_literal(&mut self, block_type: u8) {
173        self.push(interface::Command::BlockSwitchLiteral(
174            interface::LiteralBlockSwitch::new(block_type, 0),
175        ))
176    }
177}
178
179#[cfg(feature = "std")]
180fn warn_on_missing_free() {
181    let _err = ::std::io::stderr()
182        .write(b"Need to free entropy_tally_scratch before dropping CommandQueue\n");
183}
184#[cfg(not(feature = "std"))]
185fn warn_on_missing_free() {
186    // no way to warn in this case
187}
188impl<'a, Alloc: BrotliAlloc> Drop for CommandQueue<'a, Alloc> {
189    fn drop(&mut self) {
190        if !self.entropy_tally_scratch.is_free() {
191            warn_on_missing_free();
192        }
193    }
194}
195#[cfg(not(feature = "billing"))]
196fn best_singleton_speed_log(_name: &str, _data: &[SpeedAndMax; 2], _cost: &[floatX; 2]) {}
197#[cfg(feature = "billing")]
198fn best_singleton_speed_log(name: &str, data: &[SpeedAndMax; 2], cost: &[floatX; 2]) {
199    println!(
200        "{} hi cost: {} lo cost: {}   speeds {:?} {:?}",
201        name, cost[1], cost[0], data[1], data[0]
202    );
203}
204
205#[cfg(not(feature = "billing"))]
206fn best_speed_log(_name: &str, _data: &[SpeedAndMax; 2], _cost: &[floatX; 2]) {}
207#[cfg(feature = "billing")]
208fn best_speed_log(name: &str, data: &[SpeedAndMax; 2], cost: &[floatX; 2]) {
209    for high in 0..2 {
210        println!(
211            "{} Speed [ inc: {}, max: {}, algo: {} ] cost: {}",
212            name,
213            if high != 0 { "hi" } else { "lo" },
214            data[high].0,
215            data[high].1,
216            cost[high]
217        );
218    }
219}
220
221fn process_command_queue<'a, CmdProcessor: interface::CommandProcessor<'a>>(
222    command_queue: &mut CmdProcessor,
223    input: InputPair<'a>,
224    commands: &[Command],
225    dist_cache: &[i32; kNumDistanceCacheEntries],
226    mut recoder_state: RecoderState,
227    block_type: &MetaBlockSplitRefs,
228    params: &BrotliEncoderParams,
229    context_type: Option<ContextType>,
230) -> RecoderState {
231    let mut input_iter = input;
232    let mut local_dist_cache = [0i32; kNumDistanceCacheEntries];
233    local_dist_cache.clone_from_slice(&dist_cache[..]);
234    let mut btypel_counter = 0usize;
235    let mut btypec_counter = 0usize;
236    let mut btyped_counter = 0usize;
237    let mut btypel_sub = if block_type.btypel.num_types == 1 {
238        1u32 << 31
239    } else {
240        block_type.btypel.lengths[0]
241    };
242    let mut btypec_sub = if block_type.btypec.num_types == 1 {
243        1u32 << 31
244    } else {
245        block_type.btypec.lengths[0]
246    };
247    let mut btyped_sub = if block_type.btyped.num_types == 1 {
248        1u32 << 31
249    } else {
250        block_type.btyped.lengths[0]
251    };
252    {
253        command_queue.push_block_switch_literal(0);
254    }
255    let mut mb_len = input.len();
256    for cmd in commands.iter() {
257        let (inserts, interim) = input_iter.split_at(min(cmd.insert_len_ as usize, mb_len));
258        recoder_state.num_bytes_encoded += inserts.len();
259        let _copy_cursor = input.len() - interim.len();
260        // let distance_context = cmd.distance_context();
261        let copylen_code = cmd.copy_len_code();
262
263        let (prev_dist_index, dist_offset) = cmd.distance_index_and_offset(&params.dist);
264        let final_distance: usize;
265        if prev_dist_index == 0 {
266            final_distance = dist_offset as usize;
267        } else {
268            final_distance =
269                (local_dist_cache[prev_dist_index - 1] as isize + dist_offset) as usize;
270        }
271        let copy_len = copylen_code as usize;
272        let actual_copy_len: usize;
273        let max_distance = min(
274            recoder_state.num_bytes_encoded,
275            window_size_from_lgwin(params.lgwin),
276        );
277        assert!(inserts.len() <= mb_len);
278        if inserts.len() != 0 {
279            let mut tmp_inserts = inserts;
280            while tmp_inserts.len() > btypel_sub as usize {
281                // we have to divide some:
282                let (in_a, in_b) = tmp_inserts.split_at(btypel_sub as usize);
283                if in_a.len() != 0 {
284                    if context_type.is_some() {
285                        command_queue.push_literals(&in_a);
286                    } else if params.high_entropy_detection_quality == 0 {
287                        command_queue.push_literals(&in_a);
288                    } else {
289                        command_queue.push_rand_literals(&in_a);
290                    }
291                }
292                mb_len -= in_a.len();
293                tmp_inserts = in_b;
294                btypel_counter += 1;
295                if block_type.btypel.types.len() > btypel_counter {
296                    btypel_sub = block_type.btypel.lengths[btypel_counter];
297                    command_queue
298                        .push_block_switch_literal(block_type.btypel.types[btypel_counter]);
299                } else {
300                    btypel_sub = 1u32 << 31;
301                }
302            }
303            if context_type.is_some() {
304                command_queue.push_literals(&tmp_inserts);
305            } else if params.high_entropy_detection_quality == 0 {
306                command_queue.push_literals(&tmp_inserts);
307            } else {
308                command_queue.push_rand_literals(&tmp_inserts);
309            }
310            if tmp_inserts.len() != 0 {
311                mb_len -= tmp_inserts.len();
312                btypel_sub -= tmp_inserts.len() as u32;
313            }
314        }
315        if final_distance > max_distance {
316            // is dictionary
317            assert!(copy_len >= 4);
318            assert!(copy_len < 25);
319            let dictionary_offset = final_distance - max_distance - 1;
320            let ndbits = kBrotliDictionarySizeBitsByLength[copy_len] as usize;
321            let action = dictionary_offset >> ndbits;
322            let word_sub_index = dictionary_offset & ((1 << ndbits) - 1);
323            let word_index =
324                word_sub_index * copy_len + kBrotliDictionaryOffsetsByLength[copy_len] as usize;
325            let raw_word = &kBrotliDictionary[word_index..word_index + copy_len];
326            let mut transformed_word = [0u8; 38];
327            actual_copy_len = TransformDictionaryWord(
328                &mut transformed_word[..],
329                raw_word,
330                copy_len as i32,
331                action as i32,
332            ) as usize;
333            if actual_copy_len <= mb_len {
334                command_queue.push(interface::Command::Dict(interface::DictCommand {
335                    word_size: copy_len as u8,
336                    transform: action as u8,
337                    final_size: actual_copy_len as u8,
338                    empty: 0,
339                    word_id: word_sub_index as u32,
340                }));
341                mb_len -= actual_copy_len;
342                assert_eq!(
343                    InputPair(
344                        InputReference {
345                            data: transformed_word.split_at(actual_copy_len).0,
346                            orig_offset: 0
347                        },
348                        InputReference::default()
349                    ),
350                    interim.split_at(actual_copy_len).0
351                );
352            } else if mb_len != 0 {
353                // truncated dictionary word: represent it as literals instead
354                // won't be random noise since it fits in the dictionary, so we won't check for rand
355                command_queue.push_literals(&interim.split_at(mb_len).0);
356                mb_len = 0;
357                assert_eq!(
358                    InputPair(
359                        InputReference {
360                            data: transformed_word.split_at(mb_len).0,
361                            orig_offset: 0
362                        },
363                        InputReference::default()
364                    ),
365                    interim.split_at(mb_len).0
366                );
367            }
368        } else {
369            actual_copy_len = min(mb_len, copy_len);
370            if actual_copy_len != 0 {
371                command_queue.push(interface::Command::Copy(interface::CopyCommand {
372                    distance: final_distance as u32,
373                    num_bytes: actual_copy_len as u32,
374                }));
375            }
376            mb_len -= actual_copy_len;
377            if prev_dist_index != 1 || dist_offset != 0 {
378                // update distance cache unless it's the "0 distance symbol"
379                let mut tmp_dist_cache = [0i32; kNumDistanceCacheEntries - 1];
380                tmp_dist_cache.clone_from_slice(&local_dist_cache[..kNumDistanceCacheEntries - 1]);
381                local_dist_cache[1..].clone_from_slice(&tmp_dist_cache[..]);
382                local_dist_cache[0] = final_distance as i32;
383            }
384        }
385        {
386            btypec_sub -= 1;
387            if btypec_sub == 0 {
388                btypec_counter += 1;
389                if block_type.btypec.types.len() > btypec_counter {
390                    btypec_sub = block_type.btypec.lengths[btypec_counter];
391                    command_queue.push(interface::Command::BlockSwitchCommand(
392                        interface::BlockSwitch(block_type.btypec.types[btypec_counter]),
393                    ));
394                } else {
395                    btypec_sub = 1u32 << 31;
396                }
397            }
398        }
399        if copy_len != 0 && cmd.cmd_prefix_ >= 128 {
400            btyped_sub -= 1;
401            if btyped_sub == 0 {
402                btyped_counter += 1;
403                if block_type.btyped.types.len() > btyped_counter {
404                    btyped_sub = block_type.btyped.lengths[btyped_counter];
405                    command_queue.push(interface::Command::BlockSwitchDistance(
406                        interface::BlockSwitch(block_type.btyped.types[btyped_counter]),
407                    ));
408                } else {
409                    btyped_sub = 1u32 << 31;
410                }
411            }
412        }
413
414        let (copied, remainder) = interim.split_at(actual_copy_len);
415        recoder_state.num_bytes_encoded += copied.len();
416        input_iter = remainder;
417    }
418    recoder_state
419}
420
421#[cfg_attr(feature = "hotpath", hotpath::measure)]
422fn LogMetaBlock<'a, Alloc: BrotliAlloc, Cb>(
423    alloc: &mut Alloc,
424    commands: &[Command],
425    input0: &'a [u8],
426    input1: &'a [u8],
427    dist_cache: &[i32; kNumDistanceCacheEntries],
428    recoder_state: &mut RecoderState,
429    block_type: MetaBlockSplitRefs,
430    params: &BrotliEncoderParams,
431    context_type: Option<ContextType>,
432    callback: &mut Cb,
433) where
434    Cb: FnMut(
435        &mut interface::PredictionModeContextMap<InputReferenceMut>,
436        &mut [interface::StaticCommand],
437        InputPair,
438        &mut Alloc,
439    ),
440{
441    let mut local_literal_context_map = [0u8; 256 * 64];
442    let mut local_distance_context_map = [0u8; 256 * 64 + interface::DISTANCE_CONTEXT_MAP_OFFSET];
443    assert_eq!(
444        *block_type.btypel.types.iter().max().unwrap_or(&0) as u32 + 1,
445        block_type.btypel.num_types
446    );
447    assert_eq!(
448        *block_type.btypec.types.iter().max().unwrap_or(&0) as u32 + 1,
449        block_type.btypec.num_types
450    );
451    assert_eq!(
452        *block_type.btyped.types.iter().max().unwrap_or(&0) as u32 + 1,
453        block_type.btyped.num_types
454    );
455    if block_type.literal_context_map.len() <= 256 * 64 {
456        for (index, item) in block_type.literal_context_map.iter().enumerate() {
457            local_literal_context_map[index] = *item as u8;
458        }
459    }
460    if block_type.distance_context_map.len() <= 256 * 64 {
461        for (index, item) in block_type.distance_context_map.iter().enumerate() {
462            local_distance_context_map[interface::DISTANCE_CONTEXT_MAP_OFFSET + index] =
463                *item as u8;
464        }
465    }
466
467    let mut prediction_mode = interface::PredictionModeContextMap::<InputReferenceMut> {
468        literal_context_map: InputReferenceMut {
469            data: local_literal_context_map
470                .split_at_mut(block_type.literal_context_map.len())
471                .0,
472            orig_offset: 0,
473        },
474        predmode_speed_and_distance_context_map: InputReferenceMut {
475            data: local_distance_context_map
476                .split_at_mut(
477                    interface::PredictionModeContextMap::<InputReference>::size_of_combined_array(
478                        block_type.distance_context_map.len(),
479                    ),
480                )
481                .0,
482            orig_offset: 0,
483        },
484    };
485    for item in prediction_mode.get_mixing_values_mut().iter_mut() {
486        *item = prior_eval::WhichPrior::STRIDE1 as u8;
487    }
488    prediction_mode
489        .set_stride_context_speed([params.literal_adaptation[2], params.literal_adaptation[3]]);
490    prediction_mode
491        .set_context_map_speed([params.literal_adaptation[0], params.literal_adaptation[1]]);
492    prediction_mode.set_combined_stride_context_speed([
493        params.literal_adaptation[0],
494        params.literal_adaptation[1],
495    ]);
496
497    prediction_mode.set_literal_prediction_mode(interface::LiteralPredictionModeNibble(
498        context_type.unwrap_or(ContextType::CONTEXT_LSB6) as u8,
499    ));
500    let mut entropy_tally_scratch;
501    let mut entropy_pyramid;
502    if params.stride_detection_quality == 1 || params.stride_detection_quality == 2 {
503        entropy_tally_scratch = find_stride::EntropyTally::<Alloc>::new(alloc, None);
504        entropy_pyramid = find_stride::EntropyPyramid::<Alloc>::new(alloc);
505        entropy_pyramid.populate(input0, input1, &mut entropy_tally_scratch);
506    } else {
507        entropy_tally_scratch = find_stride::EntropyTally::<Alloc>::disabled_placeholder(alloc);
508        entropy_pyramid = find_stride::EntropyPyramid::<Alloc>::disabled_placeholder(alloc);
509    }
510    let input = InputPair(
511        InputReference {
512            data: input0,
513            orig_offset: 0,
514        },
515        InputReference {
516            data: input1,
517            orig_offset: input0.len(),
518        },
519    );
520    let mut best_strides = alloc_default::<u8, Alloc>();
521    if params.stride_detection_quality > 2 {
522        let mut stride_selector =
523            stride_eval::StrideEval::<Alloc>::new(alloc, input, &prediction_mode, params);
524        process_command_queue(
525            &mut stride_selector,
526            input,
527            commands,
528            dist_cache,
529            *recoder_state,
530            &block_type,
531            params,
532            context_type,
533        );
534        let ntypes = stride_selector.num_types();
535        best_strides = allocate::<u8, _>(stride_selector.alloc(), ntypes);
536        stride_selector.choose_stride(best_strides.slice_mut());
537    }
538    let mut context_map_entropy = ContextMapEntropy::<Alloc>::new(
539        alloc,
540        input,
541        entropy_pyramid.stride_last_level_range(),
542        prediction_mode,
543        params.cdf_adaptation_detection,
544    );
545    if params.cdf_adaptation_detection != 0 {
546        process_command_queue(
547            &mut context_map_entropy,
548            input,
549            commands,
550            dist_cache,
551            *recoder_state,
552            &block_type,
553            params,
554            context_type,
555        );
556        {
557            let (cm_speed, cm_cost) = context_map_entropy.best_singleton_speeds(true, false);
558            let (stride_speed, stride_cost) =
559                context_map_entropy.best_singleton_speeds(false, false);
560            let (combined_speed, combined_cost) =
561                context_map_entropy.best_singleton_speeds(false, true);
562            best_singleton_speed_log("CM", &cm_speed, &cm_cost);
563            best_singleton_speed_log("stride", &stride_speed, &stride_cost);
564            best_singleton_speed_log("combined", &combined_speed, &combined_cost);
565        }
566
567        let cm_speed = context_map_entropy.best_speeds(true, false);
568        let stride_speed = context_map_entropy.best_speeds(false, false);
569        let combined_speed = context_map_entropy.best_speeds(false, true);
570        let acost = context_map_entropy.best_speeds_costs(true, false);
571        let bcost = context_map_entropy.best_speeds_costs(false, false);
572        let ccost = context_map_entropy.best_speeds_costs(false, true);
573        context_map_entropy
574            .prediction_mode_mut()
575            .set_stride_context_speed(speed_to_tuple(stride_speed));
576        context_map_entropy
577            .prediction_mode_mut()
578            .set_context_map_speed(speed_to_tuple(cm_speed));
579        context_map_entropy
580            .prediction_mode_mut()
581            .set_combined_stride_context_speed(speed_to_tuple(combined_speed));
582
583        best_speed_log("CM", &cm_speed, &acost);
584        best_speed_log("Stride", &stride_speed, &bcost);
585        best_speed_log("StrideCombined", &combined_speed, &ccost);
586    }
587    let mut prior_selector = prior_eval::PriorEval::<Alloc>::new(
588        alloc,
589        input,
590        entropy_pyramid.stride_last_level_range(),
591        context_map_entropy.take_prediction_mode(),
592        params,
593    );
594    if params.prior_bitmask_detection != 0 {
595        process_command_queue(
596            &mut prior_selector,
597            input,
598            commands,
599            dist_cache,
600            *recoder_state,
601            &block_type,
602            params,
603            context_type,
604        );
605        prior_selector.choose_bitmask();
606    }
607    let prediction_mode = prior_selector.take_prediction_mode();
608    prior_selector.free(alloc);
609    let mut command_queue = CommandQueue::new(
610        alloc,
611        commands.len(),
612        prediction_mode,
613        input,
614        params.stride_detection_quality,
615        params.high_entropy_detection_quality,
616        context_map_entropy,
617        best_strides,
618        entropy_tally_scratch,
619        entropy_pyramid,
620    );
621
622    *recoder_state = process_command_queue(
623        &mut command_queue,
624        input,
625        commands,
626        dist_cache,
627        *recoder_state,
628        &block_type,
629        params,
630        context_type,
631    );
632    command_queue.free(callback).unwrap();
633    //   ::std::io::stderr().write(input0).unwrap();
634    //   ::std::io::stderr().write(input1).unwrap();
635}
636
637static kBlockLengthPrefixCode: [PrefixCodeRange; BROTLI_NUM_BLOCK_LEN_SYMBOLS] = [
638    PrefixCodeRange {
639        offset: 1u32,
640        nbits: 2u32,
641    },
642    PrefixCodeRange {
643        offset: 5u32,
644        nbits: 2u32,
645    },
646    PrefixCodeRange {
647        offset: 9u32,
648        nbits: 2u32,
649    },
650    PrefixCodeRange {
651        offset: 13u32,
652        nbits: 2u32,
653    },
654    PrefixCodeRange {
655        offset: 17u32,
656        nbits: 3u32,
657    },
658    PrefixCodeRange {
659        offset: 25u32,
660        nbits: 3u32,
661    },
662    PrefixCodeRange {
663        offset: 33u32,
664        nbits: 3u32,
665    },
666    PrefixCodeRange {
667        offset: 41u32,
668        nbits: 3u32,
669    },
670    PrefixCodeRange {
671        offset: 49u32,
672        nbits: 4u32,
673    },
674    PrefixCodeRange {
675        offset: 65u32,
676        nbits: 4u32,
677    },
678    PrefixCodeRange {
679        offset: 81u32,
680        nbits: 4u32,
681    },
682    PrefixCodeRange {
683        offset: 97u32,
684        nbits: 4u32,
685    },
686    PrefixCodeRange {
687        offset: 113u32,
688        nbits: 5u32,
689    },
690    PrefixCodeRange {
691        offset: 145u32,
692        nbits: 5u32,
693    },
694    PrefixCodeRange {
695        offset: 177u32,
696        nbits: 5u32,
697    },
698    PrefixCodeRange {
699        offset: 209u32,
700        nbits: 5u32,
701    },
702    PrefixCodeRange {
703        offset: 241u32,
704        nbits: 6u32,
705    },
706    PrefixCodeRange {
707        offset: 305u32,
708        nbits: 6u32,
709    },
710    PrefixCodeRange {
711        offset: 369u32,
712        nbits: 7u32,
713    },
714    PrefixCodeRange {
715        offset: 497u32,
716        nbits: 8u32,
717    },
718    PrefixCodeRange {
719        offset: 753u32,
720        nbits: 9u32,
721    },
722    PrefixCodeRange {
723        offset: 1265u32,
724        nbits: 10u32,
725    },
726    PrefixCodeRange {
727        offset: 2289u32,
728        nbits: 11u32,
729    },
730    PrefixCodeRange {
731        offset: 4337u32,
732        nbits: 12u32,
733    },
734    PrefixCodeRange {
735        offset: 8433u32,
736        nbits: 13u32,
737    },
738    PrefixCodeRange {
739        offset: 16625u32,
740        nbits: 24u32,
741    },
742];
743
744fn BrotliWriteBits(n_bits: u8, bits: u64, pos: &mut usize, array: &mut [u8]) {
745    assert_eq!(bits >> n_bits, 0);
746    assert!(n_bits <= 56);
747    let ptr_offset: usize = ((*pos >> 3) as u32) as usize;
748    let mut v = array[ptr_offset] as u64;
749    v |= bits << ((*pos) as u64 & 7);
750    array[ptr_offset + 7] = (v >> 56) as u8;
751    array[ptr_offset + 6] = ((v >> 48) & 0xff) as u8;
752    array[ptr_offset + 5] = ((v >> 40) & 0xff) as u8;
753    array[ptr_offset + 4] = ((v >> 32) & 0xff) as u8;
754    array[ptr_offset + 3] = ((v >> 24) & 0xff) as u8;
755    array[ptr_offset + 2] = ((v >> 16) & 0xff) as u8;
756    array[ptr_offset + 1] = ((v >> 8) & 0xff) as u8;
757    array[ptr_offset] = (v & 0xff) as u8;
758    *pos += n_bits as usize
759}
760
761fn BrotliWriteBitsPrepareStorage(pos: usize, array: &mut [u8]) {
762    assert_eq!(pos & 7, 0);
763    array[pos >> 3] = 0;
764}
765
766fn BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
767    num_codes: i32,
768    code_length_bitdepth: &[u8],
769    storage_ix: &mut usize,
770    storage: &mut [u8],
771) {
772    static kStorageOrder: [u8; 18] = [1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15];
773    static kHuffmanBitLengthHuffmanCodeSymbols: [u8; 6] = [0, 7, 3, 2, 1, 15];
774    static kHuffmanBitLengthHuffmanCodeBitLengths: [u8; 6] = [2, 4, 3, 2, 2, 4];
775    let mut skip_some: u64 = 0u64;
776    let mut codes_to_store: u64 = 18;
777    if num_codes > 1i32 {
778        'break5: while codes_to_store > 0 {
779            {
780                if code_length_bitdepth
781                    [(kStorageOrder[codes_to_store.wrapping_sub(1) as usize] as usize)]
782                    as i32
783                    != 0i32
784                {
785                    break 'break5;
786                }
787            }
788            codes_to_store = codes_to_store.wrapping_sub(1);
789        }
790    }
791    if code_length_bitdepth[(kStorageOrder[0] as usize)] as i32 == 0i32
792        && (code_length_bitdepth[(kStorageOrder[1] as usize)] as i32 == 0i32)
793    {
794        skip_some = 2;
795        if code_length_bitdepth[(kStorageOrder[2] as usize)] as i32 == 0i32 {
796            skip_some = 3;
797        }
798    }
799    BrotliWriteBits(2, skip_some, storage_ix, storage);
800
801    for i in skip_some..codes_to_store {
802        let l = code_length_bitdepth[kStorageOrder[i as usize] as usize] as usize;
803        BrotliWriteBits(
804            kHuffmanBitLengthHuffmanCodeBitLengths[l],
805            kHuffmanBitLengthHuffmanCodeSymbols[l] as u64,
806            storage_ix,
807            storage,
808        );
809    }
810}
811
812fn BrotliStoreHuffmanTreeToBitMask(
813    huffman_tree_size: usize,
814    huffman_tree: &[u8],
815    huffman_tree_extra_bits: &[u8],
816    code_length_bitdepth: &[u8],
817    code_length_bitdepth_symbols: &[u16],
818    storage_ix: &mut usize,
819    storage: &mut [u8],
820) {
821    for i in 0usize..huffman_tree_size {
822        let ix: usize = huffman_tree[i] as usize;
823        BrotliWriteBits(
824            code_length_bitdepth[ix],
825            code_length_bitdepth_symbols[ix] as (u64),
826            storage_ix,
827            storage,
828        );
829        if ix == 16usize {
830            BrotliWriteBits(2, huffman_tree_extra_bits[i] as (u64), storage_ix, storage);
831        } else if ix == 17usize {
832            BrotliWriteBits(3, huffman_tree_extra_bits[i] as (u64), storage_ix, storage);
833        }
834    }
835}
836
837pub fn BrotliStoreHuffmanTree(
838    depths: &[u8],
839    num: usize,
840    tree: &mut [HuffmanTree],
841    storage_ix: &mut usize,
842    storage: &mut [u8],
843) {
844    let mut huffman_tree = [0u8; 704];
845    let mut huffman_tree_extra_bits = [0u8; 704];
846    let mut huffman_tree_size = 0usize;
847    let mut code_length_bitdepth = [0u8; 18];
848    let mut code_length_bitdepth_symbols = [0u16; 18];
849    let mut huffman_tree_histogram = [0u32; 18];
850    let mut i: usize;
851    let mut num_codes: i32 = 0i32;
852    let mut code: usize = 0usize;
853
854    BrotliWriteHuffmanTree(
855        depths,
856        num,
857        &mut huffman_tree_size,
858        &mut huffman_tree[..],
859        &mut huffman_tree_extra_bits[..],
860    );
861    for i in 0usize..huffman_tree_size {
862        let _rhs = 1;
863        let _lhs = &mut huffman_tree_histogram[huffman_tree[i] as usize];
864        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
865    }
866    i = 0usize;
867    'break3: while i < 18usize {
868        {
869            if huffman_tree_histogram[i] != 0 {
870                if num_codes == 0i32 {
871                    code = i;
872                    num_codes = 1i32;
873                } else if num_codes == 1i32 {
874                    num_codes = 2i32;
875                    {
876                        break 'break3;
877                    }
878                }
879            }
880        }
881        i = i.wrapping_add(1);
882    }
883    BrotliCreateHuffmanTree(
884        &mut huffman_tree_histogram,
885        18usize,
886        5i32,
887        tree,
888        &mut code_length_bitdepth,
889    );
890    BrotliConvertBitDepthsToSymbols(
891        &mut code_length_bitdepth,
892        18usize,
893        &mut code_length_bitdepth_symbols,
894    );
895    BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
896        num_codes,
897        &code_length_bitdepth,
898        storage_ix,
899        storage,
900    );
901    if num_codes == 1i32 {
902        code_length_bitdepth[code] = 0u8;
903    }
904    BrotliStoreHuffmanTreeToBitMask(
905        huffman_tree_size,
906        &huffman_tree,
907        &huffman_tree_extra_bits,
908        &code_length_bitdepth,
909        &code_length_bitdepth_symbols,
910        storage_ix,
911        storage,
912    );
913}
914
915fn StoreStaticCodeLengthCode(storage_ix: &mut usize, storage: &mut [u8]) {
916    BrotliWriteBits(40, 0xff_5555_5554, storage_ix, storage);
917}
918
919pub struct SimpleSortHuffmanTree {}
920
921impl HuffmanComparator for SimpleSortHuffmanTree {
922    fn Cmp(&self, v0: &HuffmanTree, v1: &HuffmanTree) -> bool {
923        v0.total_count_ < v1.total_count_
924    }
925}
926
927pub fn BrotliBuildAndStoreHuffmanTreeFast<AllocHT: alloc::Allocator<HuffmanTree>>(
928    m: &mut AllocHT,
929    histogram: &[u32],
930    histogram_total: usize,
931    max_bits: usize,
932    depth: &mut [u8],
933    bits: &mut [u16],
934    storage_ix: &mut usize,
935    storage: &mut [u8],
936) {
937    let mut count: u64 = 0;
938    let mut symbols: [u64; 4] = [0; 4];
939    let mut length: u64 = 0;
940    let mut total: usize = histogram_total;
941    while total != 0usize {
942        if histogram[(length as usize)] != 0 {
943            if count < 4 {
944                symbols[count as usize] = length;
945            }
946            count = count.wrapping_add(1);
947            total = total.wrapping_sub(histogram[(length as usize)] as usize);
948        }
949        length = length.wrapping_add(1);
950    }
951    if count <= 1 {
952        BrotliWriteBits(4, 1, storage_ix, storage);
953        BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
954        depth[symbols[0] as usize] = 0u8;
955        bits[symbols[0] as usize] = 0u16;
956        return;
957    }
958    for depth_elem in depth[..(length as usize)].iter_mut() {
959        *depth_elem = 0; // memset
960    }
961    {
962        // FIXME: computation in u64, followed by allocation which might be less than u64
963        let max_tree_size: u64 = (2u64).wrapping_mul(length).wrapping_add(1);
964        // FIXME: makes little sense to test if N+1 > 0 -- always true unless wrapping. Perhaps use allocate() instead?
965        let mut tree = alloc_or_default::<HuffmanTree, _>(m, max_tree_size as usize);
966        let mut count_limit: u32;
967        count_limit = 1u32;
968        'break11: loop {
969            {
970                let mut node_index: u32 = 0u32;
971                let mut l: u64;
972                l = length;
973                while l != 0 {
974                    l = l.wrapping_sub(1);
975                    if histogram[l as usize] != 0 {
976                        if histogram[l as usize] >= count_limit {
977                            tree.slice_mut()[node_index as usize] =
978                                HuffmanTree::new(histogram[l as usize], -1, l as i16);
979                        } else {
980                            tree.slice_mut()[node_index as usize] =
981                                HuffmanTree::new(count_limit, -1, l as i16);
982                        }
983                        node_index = node_index.wrapping_add(1);
984                    }
985                }
986                {
987                    let n: i32 = node_index as i32;
988
989                    let mut i: i32 = 0i32;
990                    let mut j: i32 = n + 1i32;
991                    let mut k: i32;
992                    SortHuffmanTreeItems(tree.slice_mut(), n as usize, SimpleSortHuffmanTree {});
993                    let sentinel = HuffmanTree::new(u32::MAX, -1, -1);
994                    tree.slice_mut()[(node_index.wrapping_add(1) as usize)] = sentinel;
995                    tree.slice_mut()[(node_index as usize)] = sentinel;
996                    node_index = node_index.wrapping_add(2);
997                    k = n - 1i32;
998                    while k > 0i32 {
999                        {
1000                            let left: i32;
1001                            let right: i32;
1002                            if (tree.slice()[(i as usize)]).total_count_
1003                                <= (tree.slice()[(j as usize)]).total_count_
1004                            {
1005                                left = i;
1006                                i += 1;
1007                            } else {
1008                                left = j;
1009                                j += 1;
1010                            }
1011                            if (tree.slice()[(i as usize)]).total_count_
1012                                <= (tree.slice()[(j as usize)]).total_count_
1013                            {
1014                                right = i;
1015                                i += 1;
1016                            } else {
1017                                right = j;
1018                                j += 1;
1019                            }
1020                            let sum_total = (tree.slice()[(left as usize)])
1021                                .total_count_
1022                                .wrapping_add((tree.slice()[(right as usize)]).total_count_);
1023                            let tree_ind = (node_index.wrapping_sub(1) as usize);
1024                            (tree.slice_mut()[tree_ind]).total_count_ = sum_total;
1025                            (tree.slice_mut()[tree_ind]).index_left_ = left as i16;
1026                            (tree.slice_mut()[tree_ind]).index_right_or_value_ = right as i16;
1027                            tree.slice_mut()[(node_index as usize)] = sentinel;
1028                            node_index = node_index.wrapping_add(1);
1029                        }
1030                        k -= 1;
1031                    }
1032                    if BrotliSetDepth(2i32 * n - 1i32, tree.slice_mut(), depth, 14i32) {
1033                        break 'break11;
1034                    }
1035                }
1036            }
1037            count_limit = count_limit.wrapping_mul(2);
1038        }
1039        {
1040            m.free_cell(core::mem::take(&mut tree));
1041        }
1042    }
1043    BrotliConvertBitDepthsToSymbols(depth, length as usize, bits);
1044    if count <= 4 {
1045        BrotliWriteBits(2, 1, storage_ix, storage);
1046        BrotliWriteBits(2, count.wrapping_sub(1), storage_ix, storage);
1047        for i in 0..count as usize {
1048            for j in i + 1..count as usize {
1049                if depth[symbols[j] as usize] < depth[symbols[i] as usize] {
1050                    symbols.swap(j, i);
1051                }
1052            }
1053        }
1054        if count == 2 {
1055            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1056            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1057        } else if count == 3 {
1058            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1059            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1060            BrotliWriteBits(max_bits as u8, symbols[2], storage_ix, storage);
1061        } else {
1062            BrotliWriteBits(max_bits as u8, symbols[0], storage_ix, storage);
1063            BrotliWriteBits(max_bits as u8, symbols[1], storage_ix, storage);
1064            BrotliWriteBits(max_bits as u8, symbols[2], storage_ix, storage);
1065            BrotliWriteBits(max_bits as u8, symbols[3], storage_ix, storage);
1066            BrotliWriteBits(
1067                1,
1068                if depth[(symbols[0] as usize)] as i32 == 1i32 {
1069                    1i32
1070                } else {
1071                    0i32
1072                } as (u64),
1073                storage_ix,
1074                storage,
1075            );
1076        }
1077    } else {
1078        let mut previous_value: u8 = 8u8;
1079        let mut i: u64;
1080        StoreStaticCodeLengthCode(storage_ix, storage);
1081        i = 0;
1082        while i < length {
1083            let value: u8 = depth[(i as usize)];
1084            let mut reps: u64 = 1;
1085            let mut k: u64;
1086            k = i.wrapping_add(1);
1087            while k < length && (depth[(k as usize)] as i32 == value as i32) {
1088                {
1089                    reps = reps.wrapping_add(1);
1090                }
1091                k = k.wrapping_add(1);
1092            }
1093            i = i.wrapping_add(reps);
1094            if value as i32 == 0i32 {
1095                BrotliWriteBits(
1096                    kZeroRepsDepth[reps as usize] as u8,
1097                    kZeroRepsBits[reps as usize] as u64,
1098                    storage_ix,
1099                    storage,
1100                );
1101            } else {
1102                if previous_value as i32 != value as i32 {
1103                    BrotliWriteBits(
1104                        kCodeLengthDepth[value as usize],
1105                        kCodeLengthBits[value as usize] as (u64),
1106                        storage_ix,
1107                        storage,
1108                    );
1109                    reps = reps.wrapping_sub(1);
1110                }
1111                if reps < 3 {
1112                    while reps != 0 {
1113                        reps = reps.wrapping_sub(1);
1114                        BrotliWriteBits(
1115                            kCodeLengthDepth[value as usize],
1116                            kCodeLengthBits[value as usize] as (u64),
1117                            storage_ix,
1118                            storage,
1119                        );
1120                    }
1121                } else {
1122                    reps = reps.wrapping_sub(3);
1123                    BrotliWriteBits(
1124                        kNonZeroRepsDepth[reps as usize] as u8,
1125                        kNonZeroRepsBits[reps as usize] as u64,
1126                        storage_ix,
1127                        storage,
1128                    );
1129                }
1130                previous_value = value;
1131            }
1132        }
1133    }
1134}
1135
1136pub struct MetaBlockSplit<
1137    Alloc: alloc::Allocator<u8>
1138        + alloc::Allocator<u32>
1139        + alloc::Allocator<HistogramLiteral>
1140        + alloc::Allocator<HistogramCommand>
1141        + alloc::Allocator<HistogramDistance>,
1142> {
1143    pub literal_split: BlockSplit<Alloc>,
1144    pub command_split: BlockSplit<Alloc>,
1145    pub distance_split: BlockSplit<Alloc>,
1146    pub literal_context_map: <Alloc as Allocator<u32>>::AllocatedMemory,
1147    pub literal_context_map_size: usize,
1148    pub distance_context_map: <Alloc as Allocator<u32>>::AllocatedMemory,
1149    pub distance_context_map_size: usize,
1150    pub literal_histograms: <Alloc as Allocator<HistogramLiteral>>::AllocatedMemory,
1151    pub literal_histograms_size: usize,
1152    pub command_histograms: <Alloc as Allocator<HistogramCommand>>::AllocatedMemory,
1153    pub command_histograms_size: usize,
1154    pub distance_histograms: <Alloc as Allocator<HistogramDistance>>::AllocatedMemory,
1155    pub distance_histograms_size: usize,
1156}
1157impl<
1158    Alloc: alloc::Allocator<u8>
1159        + alloc::Allocator<u32>
1160        + alloc::Allocator<HistogramLiteral>
1161        + alloc::Allocator<HistogramCommand>
1162        + alloc::Allocator<HistogramDistance>,
1163> Default for MetaBlockSplit<Alloc>
1164{
1165    fn default() -> Self {
1166        Self {
1167            literal_split: BlockSplit::default(),
1168            command_split: BlockSplit::default(),
1169            distance_split: BlockSplit::default(),
1170            literal_context_map: alloc_default::<u32, Alloc>(),
1171            literal_context_map_size: 0,
1172            distance_context_map: alloc_default::<u32, Alloc>(),
1173            distance_context_map_size: 0,
1174            literal_histograms: alloc_default::<HistogramLiteral, Alloc>(),
1175            literal_histograms_size: 0,
1176            command_histograms: alloc_default::<HistogramCommand, Alloc>(),
1177            command_histograms_size: 0,
1178            distance_histograms: alloc_default::<HistogramDistance, Alloc>(),
1179            distance_histograms_size: 0,
1180        }
1181    }
1182}
1183
1184impl<
1185    Alloc: alloc::Allocator<u8>
1186        + alloc::Allocator<u32>
1187        + alloc::Allocator<HistogramLiteral>
1188        + alloc::Allocator<HistogramCommand>
1189        + alloc::Allocator<HistogramDistance>,
1190> MetaBlockSplit<Alloc>
1191{
1192    pub fn new() -> Self {
1193        Self::default()
1194    }
1195
1196    pub fn destroy(&mut self, alloc: &mut Alloc) {
1197        self.literal_split.destroy(alloc);
1198        self.command_split.destroy(alloc);
1199        self.distance_split.destroy(alloc);
1200        <Alloc as Allocator<u32>>::free_cell(alloc, core::mem::take(&mut self.literal_context_map));
1201        self.literal_context_map_size = 0;
1202        <Alloc as Allocator<u32>>::free_cell(
1203            alloc,
1204            core::mem::take(&mut self.distance_context_map),
1205        );
1206        self.distance_context_map_size = 0;
1207        <Alloc as Allocator<HistogramLiteral>>::free_cell(
1208            alloc,
1209            core::mem::take(&mut self.literal_histograms),
1210        );
1211
1212        self.literal_histograms_size = 0;
1213        <Alloc as Allocator<HistogramCommand>>::free_cell(
1214            alloc,
1215            core::mem::take(&mut self.command_histograms),
1216        );
1217        self.command_histograms_size = 0;
1218        <Alloc as Allocator<HistogramDistance>>::free_cell(
1219            alloc,
1220            core::mem::take(&mut self.distance_histograms),
1221        );
1222        self.distance_histograms_size = 0;
1223    }
1224}
1225#[derive(Clone, Copy)]
1226pub struct BlockTypeCodeCalculator {
1227    pub last_type: usize,
1228    pub second_last_type: usize,
1229}
1230
1231pub struct BlockSplitCode {
1232    pub type_code_calculator: BlockTypeCodeCalculator,
1233    pub type_depths: [u8; 258],
1234    pub type_bits: [u16; 258],
1235    pub length_depths: [u8; 26],
1236    pub length_bits: [u16; 26],
1237}
1238
1239pub struct BlockEncoder<'a, Alloc: alloc::Allocator<u8> + alloc::Allocator<u16>> {
1240    /*    pub alloc_u8 : AllocU8,
1241    pub alloc_u16 : AllocU16,
1242    pub alloc_u32 : AllocU32,
1243    pub alloc_ht : AllocHT,*/
1244    pub histogram_length_: usize,
1245    pub num_block_types_: usize,
1246    pub block_types_: &'a [u8],
1247    pub block_lengths_: &'a [u32],
1248    pub num_blocks_: usize,
1249    pub block_split_code_: BlockSplitCode,
1250    pub block_ix_: usize,
1251    pub block_len_: usize,
1252    pub entropy_ix_: usize,
1253    pub depths_: <Alloc as Allocator<u8>>::AllocatedMemory,
1254    pub bits_: <Alloc as Allocator<u16>>::AllocatedMemory,
1255}
1256
1257fn Log2FloorNonZero(mut n: u64) -> u32 {
1258    let mut result: u32 = 0u32;
1259    'loop1: loop {
1260        if {
1261            n >>= 1i32;
1262            n
1263        } != 0
1264        {
1265            result = result.wrapping_add(1);
1266            continue 'loop1;
1267        } else {
1268            break 'loop1;
1269        }
1270    }
1271    result
1272}
1273
1274fn BrotliEncodeMlen(length: u32, bits: &mut u64, numbits: &mut u32, nibblesbits: &mut u32) {
1275    let lg: u32 = (if length == 1u32 {
1276        1u32
1277    } else {
1278        Log2FloorNonZero(length.wrapping_sub(1) as (u64)).wrapping_add(1)
1279    });
1280    let mnibbles: u32 = (if lg < 16u32 {
1281        16u32
1282    } else {
1283        lg.wrapping_add(3)
1284    })
1285    .wrapping_div(4);
1286    assert!(length > 0);
1287    assert!(length <= (1 << 24));
1288    assert!(lg <= 24);
1289    *nibblesbits = mnibbles.wrapping_sub(4);
1290    *numbits = mnibbles.wrapping_mul(4);
1291    *bits = length.wrapping_sub(1) as u64;
1292}
1293
1294fn StoreCompressedMetaBlockHeader(
1295    is_final_block: bool,
1296    length: usize,
1297    storage_ix: &mut usize,
1298    storage: &mut [u8],
1299) {
1300    let mut lenbits: u64 = 0;
1301    let mut nlenbits: u32 = 0;
1302    let mut nibblesbits: u32 = 0;
1303    BrotliWriteBits(1, is_final_block.into(), storage_ix, storage);
1304    if is_final_block {
1305        BrotliWriteBits(1, 0, storage_ix, storage);
1306    }
1307    BrotliEncodeMlen(length as u32, &mut lenbits, &mut nlenbits, &mut nibblesbits);
1308    BrotliWriteBits(2, nibblesbits as u64, storage_ix, storage);
1309    BrotliWriteBits(nlenbits as u8, lenbits, storage_ix, storage);
1310    if !is_final_block {
1311        BrotliWriteBits(1, 0, storage_ix, storage);
1312    }
1313}
1314
1315impl BlockTypeCodeCalculator {
1316    fn new() -> Self {
1317        Self {
1318            last_type: 1,
1319            second_last_type: 0,
1320        }
1321    }
1322}
1323
1324impl<'a, Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'a, Alloc> {
1325    fn new(
1326        histogram_length: usize,
1327        num_block_types: usize,
1328        block_types: &'a [u8],
1329        block_lengths: &'a [u32],
1330        num_blocks: usize,
1331    ) -> Self {
1332        let block_len = if num_blocks != 0 && !block_lengths.is_empty() {
1333            block_lengths[0] as usize
1334        } else {
1335            0
1336        };
1337        Self {
1338            histogram_length_: histogram_length,
1339            num_block_types_: num_block_types,
1340            block_types_: block_types,
1341            block_lengths_: block_lengths,
1342            num_blocks_: num_blocks,
1343            block_split_code_: BlockSplitCode {
1344                type_code_calculator: BlockTypeCodeCalculator::new(),
1345                type_depths: [0; 258],
1346                type_bits: [0; 258],
1347                length_depths: [0; 26],
1348                length_bits: [0; 26],
1349            },
1350            block_ix_: 0,
1351            block_len_: block_len,
1352            entropy_ix_: 0,
1353            depths_: alloc_default::<u8, Alloc>(),
1354            bits_: alloc_default::<u16, Alloc>(),
1355        }
1356    }
1357}
1358
1359fn NextBlockTypeCode(calculator: &mut BlockTypeCodeCalculator, type_: u8) -> usize {
1360    let type_code: usize = (if type_ as usize == calculator.last_type.wrapping_add(1) {
1361        1u32
1362    } else if type_ as usize == calculator.second_last_type {
1363        0u32
1364    } else {
1365        (type_ as u32).wrapping_add(2)
1366    }) as usize;
1367    calculator.second_last_type = calculator.last_type;
1368    calculator.last_type = type_ as usize;
1369    type_code
1370}
1371
1372fn BlockLengthPrefixCode(len: u32) -> u32 {
1373    let mut code: u32 = (if len >= 177u32 {
1374        if len >= 753u32 { 20i32 } else { 14i32 }
1375    } else if len >= 41u32 {
1376        7i32
1377    } else {
1378        0i32
1379    }) as u32;
1380    while code < (26i32 - 1i32) as u32
1381        && (len >= kBlockLengthPrefixCode[code.wrapping_add(1) as usize].offset)
1382    {
1383        code = code.wrapping_add(1);
1384    }
1385    code
1386}
1387
1388fn StoreVarLenUint8(n: u64, storage_ix: &mut usize, storage: &mut [u8]) {
1389    if n == 0 {
1390        BrotliWriteBits(1, 0, storage_ix, storage);
1391    } else {
1392        let nbits: u8 = Log2FloorNonZero(n) as u8;
1393        BrotliWriteBits(1, 1, storage_ix, storage);
1394        BrotliWriteBits(3, nbits as u64, storage_ix, storage);
1395        BrotliWriteBits(nbits, n.wrapping_sub(1u64 << nbits), storage_ix, storage);
1396    }
1397}
1398
1399fn StoreSimpleHuffmanTree(
1400    depths: &[u8],
1401    symbols: &mut [usize],
1402    num_symbols: usize,
1403    max_bits: usize,
1404    storage_ix: &mut usize,
1405    storage: &mut [u8],
1406) {
1407    BrotliWriteBits(2, 1, storage_ix, storage);
1408    BrotliWriteBits(2, num_symbols.wrapping_sub(1) as u64, storage_ix, storage);
1409    {
1410        for i in 0..num_symbols {
1411            for j in i + 1..num_symbols {
1412                if depths[symbols[j]] < depths[symbols[i]] {
1413                    symbols.swap(j, i);
1414                }
1415            }
1416        }
1417    }
1418    if num_symbols == 2usize {
1419        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1420        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1421    } else if num_symbols == 3usize {
1422        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1423        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1424        BrotliWriteBits(max_bits as u8, symbols[2] as u64, storage_ix, storage);
1425    } else {
1426        BrotliWriteBits(max_bits as u8, symbols[0] as u64, storage_ix, storage);
1427        BrotliWriteBits(max_bits as u8, symbols[1] as u64, storage_ix, storage);
1428        BrotliWriteBits(max_bits as u8, symbols[2] as u64, storage_ix, storage);
1429        BrotliWriteBits(max_bits as u8, symbols[3] as u64, storage_ix, storage);
1430        BrotliWriteBits(
1431            1,
1432            if depths[symbols[0]] as i32 == 1i32 {
1433                1i32
1434            } else {
1435                0i32
1436            } as (u64),
1437            storage_ix,
1438            storage,
1439        );
1440    }
1441}
1442
1443fn BuildAndStoreHuffmanTree(
1444    histogram: &[u32],
1445    histogram_length: usize,
1446    alphabet_size: usize,
1447    tree: &mut [HuffmanTree],
1448    depth: &mut [u8],
1449    bits: &mut [u16],
1450    storage_ix: &mut usize,
1451    storage: &mut [u8],
1452) {
1453    let mut count: usize = 0usize;
1454    let mut s4 = [0usize; 4];
1455    let mut i: usize;
1456    let mut max_bits: usize = 0usize;
1457    i = 0usize;
1458    'break31: while i < histogram_length {
1459        {
1460            if histogram[i] != 0 {
1461                if count < 4usize {
1462                    s4[count] = i;
1463                } else if count > 4usize {
1464                    break 'break31;
1465                }
1466                count = count.wrapping_add(1);
1467            }
1468        }
1469        i = i.wrapping_add(1);
1470    }
1471    {
1472        let mut max_bits_counter: usize = alphabet_size.wrapping_sub(1);
1473        while max_bits_counter != 0 {
1474            max_bits_counter >>= 1i32;
1475            max_bits = max_bits.wrapping_add(1);
1476        }
1477    }
1478    if count <= 1 {
1479        BrotliWriteBits(4, 1, storage_ix, storage);
1480        BrotliWriteBits(max_bits as u8, s4[0] as u64, storage_ix, storage);
1481        depth[s4[0]] = 0u8;
1482        bits[s4[0]] = 0u16;
1483        return;
1484    }
1485
1486    for depth_elem in depth[..histogram_length].iter_mut() {
1487        *depth_elem = 0; // memset
1488    }
1489    BrotliCreateHuffmanTree(histogram, histogram_length, 15i32, tree, depth);
1490    BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits);
1491    if count <= 4usize {
1492        StoreSimpleHuffmanTree(depth, &mut s4[..], count, max_bits, storage_ix, storage);
1493    } else {
1494        BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage);
1495    }
1496}
1497
1498fn GetBlockLengthPrefixCode(len: u32, code: &mut usize, n_extra: &mut u32, extra: &mut u32) {
1499    *code = BlockLengthPrefixCode(len) as usize;
1500    *n_extra = kBlockLengthPrefixCode[*code].nbits;
1501    *extra = len.wrapping_sub(kBlockLengthPrefixCode[*code].offset);
1502}
1503
1504fn StoreBlockSwitch(
1505    code: &mut BlockSplitCode,
1506    block_len: u32,
1507    block_type: u8,
1508    is_first_block: bool,
1509    storage_ix: &mut usize,
1510    storage: &mut [u8],
1511) {
1512    let typecode: usize = NextBlockTypeCode(&mut code.type_code_calculator, block_type);
1513    let mut lencode: usize = 0;
1514    let mut len_nextra: u32 = 0;
1515    let mut len_extra: u32 = 0;
1516    if !is_first_block {
1517        BrotliWriteBits(
1518            code.type_depths[typecode] as u8,
1519            code.type_bits[typecode] as (u64),
1520            storage_ix,
1521            storage,
1522        );
1523    }
1524    GetBlockLengthPrefixCode(block_len, &mut lencode, &mut len_nextra, &mut len_extra);
1525    BrotliWriteBits(
1526        code.length_depths[lencode],
1527        code.length_bits[lencode] as (u64),
1528        storage_ix,
1529        storage,
1530    );
1531    BrotliWriteBits(len_nextra as u8, len_extra as (u64), storage_ix, storage);
1532}
1533
1534fn BuildAndStoreBlockSplitCode(
1535    types: &[u8],
1536    lengths: &[u32],
1537    num_blocks: usize,
1538    num_types: usize,
1539    tree: &mut [HuffmanTree],
1540    code: &mut BlockSplitCode,
1541    storage_ix: &mut usize,
1542    storage: &mut [u8],
1543) {
1544    let mut type_histo: [u32; 258] = [0; 258];
1545    let mut length_histo: [u32; 26] = [0; 26];
1546    let mut i: usize;
1547    let mut type_code_calculator = BlockTypeCodeCalculator::new();
1548    i = 0usize;
1549    while i < num_blocks {
1550        {
1551            let type_code: usize = NextBlockTypeCode(&mut type_code_calculator, types[i]);
1552            if i != 0usize {
1553                let _rhs = 1;
1554                let _lhs = &mut type_histo[type_code];
1555                *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1556            }
1557            {
1558                let _rhs = 1;
1559                let _lhs = &mut length_histo[BlockLengthPrefixCode(lengths[i]) as usize];
1560                *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1561            }
1562        }
1563        i = i.wrapping_add(1);
1564    }
1565    StoreVarLenUint8(num_types.wrapping_sub(1) as u64, storage_ix, storage);
1566    if num_types > 1 {
1567        BuildAndStoreHuffmanTree(
1568            &mut type_histo[0..],
1569            num_types.wrapping_add(2),
1570            num_types.wrapping_add(2),
1571            tree,
1572            &mut code.type_depths[0..],
1573            &mut code.type_bits[0..],
1574            storage_ix,
1575            storage,
1576        );
1577        BuildAndStoreHuffmanTree(
1578            &mut length_histo[0..],
1579            super::constants::BROTLI_NUM_BLOCK_LEN_SYMBOLS, // 26
1580            super::constants::BROTLI_NUM_BLOCK_LEN_SYMBOLS,
1581            tree,
1582            &mut code.length_depths[0..],
1583            &mut code.length_bits[0..],
1584            storage_ix,
1585            storage,
1586        );
1587        StoreBlockSwitch(code, lengths[0], types[0], true, storage_ix, storage);
1588    }
1589}
1590
1591impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1592    fn build_and_store_block_switch_entropy_codes(
1593        &mut self,
1594        tree: &mut [HuffmanTree],
1595        storage_ix: &mut usize,
1596        storage: &mut [u8],
1597    ) {
1598        BuildAndStoreBlockSplitCode(
1599            self.block_types_,
1600            self.block_lengths_,
1601            self.num_blocks_,
1602            self.num_block_types_,
1603            tree,
1604            &mut self.block_split_code_,
1605            storage_ix,
1606            storage,
1607        );
1608    }
1609}
1610
1611fn StoreTrivialContextMap(
1612    num_types: usize,
1613    context_bits: usize,
1614    tree: &mut [HuffmanTree],
1615    storage_ix: &mut usize,
1616    storage: &mut [u8],
1617) {
1618    StoreVarLenUint8(num_types.wrapping_sub(1) as u64, storage_ix, storage);
1619    if num_types > 1 {
1620        let repeat_code: usize = context_bits.wrapping_sub(1u32 as usize);
1621        let repeat_bits: usize = (1u32 << repeat_code).wrapping_sub(1) as usize;
1622        let alphabet_size: usize = num_types.wrapping_add(repeat_code);
1623        let mut histogram: [u32; 272] = [0; 272];
1624        let mut depths: [u8; 272] = [0; 272];
1625        let mut bits: [u16; 272] = [0; 272];
1626        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
1627        BrotliWriteBits(4u8, repeat_code.wrapping_sub(1) as u64, storage_ix, storage);
1628        histogram[repeat_code] = num_types as u32;
1629        histogram[0] = 1;
1630        for i in context_bits..alphabet_size {
1631            histogram[i] = 1;
1632        }
1633        BuildAndStoreHuffmanTree(
1634            &mut histogram[..],
1635            alphabet_size,
1636            alphabet_size,
1637            tree,
1638            &mut depths[..],
1639            &mut bits[..],
1640            storage_ix,
1641            storage,
1642        );
1643        for i in 0usize..num_types {
1644            let code: usize = if i == 0usize {
1645                0usize
1646            } else {
1647                i.wrapping_add(context_bits).wrapping_sub(1)
1648            };
1649            BrotliWriteBits(depths[code], bits[code] as (u64), storage_ix, storage);
1650            BrotliWriteBits(
1651                depths[repeat_code],
1652                bits[repeat_code] as (u64),
1653                storage_ix,
1654                storage,
1655            );
1656            BrotliWriteBits(repeat_code as u8, repeat_bits as u64, storage_ix, storage);
1657        }
1658        BrotliWriteBits(1, 1, storage_ix, storage);
1659    }
1660}
1661
1662fn IndexOf(v: &[u8], v_size: usize, value: u8) -> usize {
1663    let mut i: usize = 0usize;
1664    while i < v_size {
1665        {
1666            if v[i] as i32 == value as i32 {
1667                return i;
1668            }
1669        }
1670        i = i.wrapping_add(1);
1671    }
1672    i
1673}
1674
1675fn MoveToFront(v: &mut [u8], index: usize) {
1676    let value: u8 = v[index];
1677    let mut i: usize;
1678    i = index;
1679    while i != 0usize {
1680        {
1681            v[i] = v[i.wrapping_sub(1)];
1682        }
1683        i = i.wrapping_sub(1);
1684    }
1685    v[0] = value;
1686}
1687
1688fn MoveToFrontTransform(v_in: &[u32], v_size: usize, v_out: &mut [u32]) {
1689    let mut mtf: [u8; 256] = [0; 256];
1690    let mut max_value: u32;
1691    if v_size == 0usize {
1692        return;
1693    }
1694    max_value = v_in[0];
1695    for i in 1..v_size {
1696        if v_in[i] > max_value {
1697            max_value = v_in[i];
1698        }
1699    }
1700    for i in 0..=max_value as usize {
1701        mtf[i] = i as u8;
1702    }
1703    {
1704        let mtf_size: usize = max_value.wrapping_add(1) as usize;
1705        for i in 0usize..v_size {
1706            let index: usize = IndexOf(&mtf[..], mtf_size, v_in[i] as u8);
1707            v_out[i] = index as u32;
1708            MoveToFront(&mut mtf[..], index);
1709        }
1710    }
1711}
1712
1713fn RunLengthCodeZeros(
1714    in_size: usize,
1715    v: &mut [u32],
1716    out_size: &mut usize,
1717    max_run_length_prefix: &mut u32,
1718) {
1719    let mut max_reps: u32 = 0u32;
1720    let mut i: usize;
1721    let mut max_prefix: u32;
1722    i = 0usize;
1723    while i < in_size {
1724        let mut reps: u32 = 0u32;
1725        while i < in_size && (v[i] != 0u32) {
1726            i = i.wrapping_add(1);
1727        }
1728        while i < in_size && (v[i] == 0u32) {
1729            {
1730                reps = reps.wrapping_add(1);
1731            }
1732            i = i.wrapping_add(1);
1733        }
1734        max_reps = max(reps, max_reps);
1735    }
1736    max_prefix = if max_reps > 0u32 {
1737        Log2FloorNonZero(max_reps as (u64))
1738    } else {
1739        0u32
1740    };
1741    max_prefix = min(max_prefix, *max_run_length_prefix);
1742    *max_run_length_prefix = max_prefix;
1743    *out_size = 0usize;
1744    i = 0usize;
1745    while i < in_size {
1746        if v[i] != 0u32 {
1747            v[*out_size] = (v[i]).wrapping_add(*max_run_length_prefix);
1748            i = i.wrapping_add(1);
1749            *out_size = out_size.wrapping_add(1);
1750        } else {
1751            let mut reps: u32 = 1u32;
1752            let mut k: usize;
1753            k = i.wrapping_add(1);
1754            while k < in_size && (v[k] == 0u32) {
1755                {
1756                    reps = reps.wrapping_add(1);
1757                }
1758                k = k.wrapping_add(1);
1759            }
1760            i = i.wrapping_add(reps as usize);
1761            while reps != 0u32 {
1762                if reps < 2u32 << max_prefix {
1763                    let run_length_prefix: u32 = Log2FloorNonZero(reps as (u64));
1764                    let extra_bits: u32 = reps.wrapping_sub(1u32 << run_length_prefix);
1765                    v[*out_size] = run_length_prefix.wrapping_add(extra_bits << 9);
1766                    *out_size = out_size.wrapping_add(1);
1767                    {
1768                        break;
1769                    }
1770                } else {
1771                    let extra_bits: u32 = (1u32 << max_prefix).wrapping_sub(1);
1772                    v[*out_size] = max_prefix.wrapping_add(extra_bits << 9);
1773                    reps = reps.wrapping_sub((2u32 << max_prefix).wrapping_sub(1));
1774                    *out_size = out_size.wrapping_add(1);
1775                }
1776            }
1777        }
1778    }
1779}
1780
1781fn EncodeContextMap<AllocU32: alloc::Allocator<u32>>(
1782    m: &mut AllocU32,
1783    context_map: &[u32],
1784    context_map_size: usize,
1785    num_clusters: usize,
1786    tree: &mut [HuffmanTree],
1787    storage_ix: &mut usize,
1788    storage: &mut [u8],
1789) {
1790    let mut rle_symbols: AllocU32::AllocatedMemory;
1791    let mut max_run_length_prefix: u32 = 6u32;
1792    let mut num_rle_symbols: usize = 0usize;
1793    static kSymbolMask: u32 = (1u32 << 9) - 1;
1794    let mut depths: [u8; 272] = [0; 272];
1795    let mut bits: [u16; 272] = [0; 272];
1796    StoreVarLenUint8(num_clusters.wrapping_sub(1) as u64, storage_ix, storage);
1797    if num_clusters == 1 {
1798        return;
1799    }
1800    rle_symbols = alloc_or_default::<u32, _>(m, context_map_size);
1801    MoveToFrontTransform(context_map, context_map_size, rle_symbols.slice_mut());
1802    RunLengthCodeZeros(
1803        context_map_size,
1804        rle_symbols.slice_mut(),
1805        &mut num_rle_symbols,
1806        &mut max_run_length_prefix,
1807    );
1808    let mut histogram: [u32; 272] = [0; 272];
1809    for i in 0usize..num_rle_symbols {
1810        let _rhs = 1;
1811        let _lhs = &mut histogram[(rle_symbols.slice()[i] & kSymbolMask) as usize];
1812        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1813    }
1814    {
1815        let use_rle = max_run_length_prefix > 0;
1816        BrotliWriteBits(1, u64::from(use_rle), storage_ix, storage);
1817        if use_rle {
1818            BrotliWriteBits(
1819                4,
1820                max_run_length_prefix.wrapping_sub(1) as (u64),
1821                storage_ix,
1822                storage,
1823            );
1824        }
1825    }
1826    BuildAndStoreHuffmanTree(
1827        &mut histogram[..],
1828        num_clusters.wrapping_add(max_run_length_prefix as usize),
1829        num_clusters.wrapping_add(max_run_length_prefix as usize),
1830        tree,
1831        &mut depths[..],
1832        &mut bits[..],
1833        storage_ix,
1834        storage,
1835    );
1836    for i in 0usize..num_rle_symbols {
1837        let rle_symbol: u32 = rle_symbols.slice()[i] & kSymbolMask;
1838        let extra_bits_val: u32 = rle_symbols.slice()[i] >> 9;
1839        BrotliWriteBits(
1840            depths[rle_symbol as usize],
1841            bits[rle_symbol as usize] as (u64),
1842            storage_ix,
1843            storage,
1844        );
1845        if rle_symbol > 0u32 && (rle_symbol <= max_run_length_prefix) {
1846            BrotliWriteBits(
1847                rle_symbol as u8,
1848                extra_bits_val as (u64),
1849                storage_ix,
1850                storage,
1851            );
1852        }
1853    }
1854    BrotliWriteBits(1, 1, storage_ix, storage);
1855    m.free_cell(rle_symbols);
1856}
1857
1858impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1859    fn build_and_store_entropy_codes<HistogramType: SliceWrapper<u32>>(
1860        &mut self,
1861        m: &mut Alloc,
1862        histograms: &[HistogramType],
1863        histograms_size: usize,
1864        alphabet_size: usize,
1865        tree: &mut [HuffmanTree],
1866        storage_ix: &mut usize,
1867        storage: &mut [u8],
1868    ) {
1869        let table_size: usize = histograms_size.wrapping_mul(self.histogram_length_);
1870        self.depths_ = alloc_or_default::<u8, _>(m, table_size);
1871        self.bits_ = alloc_or_default::<u16, _>(m, table_size);
1872        {
1873            for i in 0usize..histograms_size {
1874                let ix: usize = i.wrapping_mul(self.histogram_length_);
1875                BuildAndStoreHuffmanTree(
1876                    &(histograms[i]).slice()[0..],
1877                    self.histogram_length_,
1878                    alphabet_size,
1879                    tree,
1880                    &mut self.depths_.slice_mut()[ix..],
1881                    &mut self.bits_.slice_mut()[ix..],
1882                    storage_ix,
1883                    storage,
1884                );
1885            }
1886        }
1887    }
1888
1889    fn store_symbol(&mut self, symbol: usize, storage_ix: &mut usize, storage: &mut [u8]) {
1890        if self.block_len_ == 0usize {
1891            let block_ix: usize = {
1892                self.block_ix_ = self.block_ix_.wrapping_add(1);
1893                self.block_ix_
1894            };
1895            let block_len: u32 = self.block_lengths_[block_ix];
1896            let block_type: u8 = self.block_types_[block_ix];
1897            self.block_len_ = block_len as usize;
1898            self.entropy_ix_ = (block_type as usize).wrapping_mul(self.histogram_length_);
1899            StoreBlockSwitch(
1900                &mut self.block_split_code_,
1901                block_len,
1902                block_type,
1903                false,
1904                storage_ix,
1905                storage,
1906            );
1907        }
1908        self.block_len_ = self.block_len_.wrapping_sub(1);
1909        {
1910            let ix: usize = self.entropy_ix_.wrapping_add(symbol);
1911            BrotliWriteBits(
1912                self.depths_.slice()[ix],
1913                self.bits_.slice()[ix] as (u64),
1914                storage_ix,
1915                storage,
1916            );
1917        }
1918    }
1919}
1920
1921impl Command {
1922    fn copy_len_code(&self) -> u32 {
1923        let modifier = self.copy_len_ >> 25;
1924        let delta: i32 = ((modifier | ((modifier & 0x40) << 1)) as u8) as i8 as i32;
1925        ((self.copy_len_ & 0x01ff_ffff) as i32 + delta) as u32
1926    }
1927}
1928
1929fn GetInsertExtra(inscode: u16) -> u32 {
1930    kInsExtra[inscode as usize]
1931}
1932
1933fn GetInsertBase(inscode: u16) -> u32 {
1934    kInsBase[inscode as usize]
1935}
1936
1937fn GetCopyBase(copycode: u16) -> u32 {
1938    kCopyBase[copycode as usize]
1939}
1940
1941fn GetCopyExtra(copycode: u16) -> u32 {
1942    kCopyExtra[copycode as usize]
1943}
1944
1945fn StoreCommandExtra(cmd: &Command, storage_ix: &mut usize, storage: &mut [u8]) {
1946    let copylen_code = cmd.copy_len_code();
1947    let inscode: u16 = GetInsertLengthCode(cmd.insert_len_ as usize);
1948    let copycode: u16 = GetCopyLengthCode(copylen_code as usize);
1949    let insnumextra: u32 = GetInsertExtra(inscode);
1950    let insextraval: u64 = cmd.insert_len_.wrapping_sub(GetInsertBase(inscode)) as (u64);
1951    let copyextraval: u64 = copylen_code.wrapping_sub(GetCopyBase(copycode)) as (u64);
1952    let bits: u64 = copyextraval << insnumextra | insextraval;
1953    BrotliWriteBits(
1954        insnumextra.wrapping_add(GetCopyExtra(copycode)) as u8,
1955        bits,
1956        storage_ix,
1957        storage,
1958    );
1959}
1960
1961fn Context(p1: u8, p2: u8, mode: ContextType) -> u8 {
1962    match mode {
1963        ContextType::CONTEXT_LSB6 => (p1 as i32 & 0x3fi32) as u8,
1964        ContextType::CONTEXT_MSB6 => (p1 as i32 >> 2) as u8,
1965        ContextType::CONTEXT_UTF8 => {
1966            (kUTF8ContextLookup[p1 as usize] as i32
1967                | kUTF8ContextLookup[(p2 as i32 + 256i32) as usize] as i32) as u8
1968        }
1969        ContextType::CONTEXT_SIGNED => {
1970            (((kSigned3BitContextLookup[p1 as usize] as i32) << 3)
1971                + kSigned3BitContextLookup[p2 as usize] as i32) as u8
1972        }
1973    }
1974    //  0u8
1975}
1976
1977impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
1978    fn store_symbol_with_context(
1979        &mut self,
1980        symbol: usize,
1981        context: usize,
1982        context_map: &[u32],
1983        storage_ix: &mut usize,
1984        storage: &mut [u8],
1985        context_bits: usize,
1986    ) {
1987        if self.block_len_ == 0 {
1988            let block_ix: usize = {
1989                self.block_ix_ = self.block_ix_.wrapping_add(1);
1990                self.block_ix_
1991            };
1992            let block_len: u32 = self.block_lengths_[block_ix];
1993            let block_type: u8 = self.block_types_[block_ix];
1994            self.block_len_ = block_len as usize;
1995            self.entropy_ix_ = (block_type as usize) << context_bits;
1996            StoreBlockSwitch(
1997                &mut self.block_split_code_,
1998                block_len,
1999                block_type,
2000                false,
2001                storage_ix,
2002                storage,
2003            );
2004        }
2005        self.block_len_ = self.block_len_.wrapping_sub(1);
2006        {
2007            let histo_ix: usize = context_map[self.entropy_ix_.wrapping_add(context)] as usize;
2008            let ix: usize = histo_ix
2009                .wrapping_mul(self.histogram_length_)
2010                .wrapping_add(symbol);
2011            BrotliWriteBits(
2012                self.depths_.slice()[ix],
2013                self.bits_.slice()[ix] as (u64),
2014                storage_ix,
2015                storage,
2016            );
2017        }
2018    }
2019}
2020
2021impl<Alloc: Allocator<u8> + Allocator<u16>> BlockEncoder<'_, Alloc> {
2022    fn cleanup(&mut self, m: &mut Alloc) {
2023        <Alloc as Allocator<u8>>::free_cell(m, core::mem::take(&mut self.depths_));
2024        <Alloc as Allocator<u16>>::free_cell(m, core::mem::take(&mut self.bits_));
2025    }
2026}
2027
2028pub fn JumpToByteBoundary(storage_ix: &mut usize, storage: &mut [u8]) {
2029    *storage_ix = storage_ix.wrapping_add(7u32 as usize) & !7u32 as usize;
2030    storage[(*storage_ix >> 3)] = 0u8;
2031}
2032
2033#[cfg_attr(feature = "hotpath", hotpath::measure)]
2034pub(crate) fn store_meta_block<Alloc: BrotliAlloc, Cb>(
2035    alloc: &mut Alloc,
2036    input: &[u8],
2037    start_pos: usize,
2038    length: usize,
2039    mask: usize,
2040    mut prev_byte: u8,
2041    mut prev_byte2: u8,
2042    is_last: bool,
2043    params: &BrotliEncoderParams,
2044    literal_context_mode: ContextType,
2045    distance_cache: &[i32; kNumDistanceCacheEntries],
2046    commands: &[Command],
2047    n_commands: usize,
2048    mb: &mut MetaBlockSplit<Alloc>,
2049    recoder_state: &mut RecoderState,
2050    storage_ix: &mut usize,
2051    storage: &mut [u8],
2052    callback: &mut Cb,
2053) where
2054    Cb: FnMut(
2055        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2056        &mut [interface::StaticCommand],
2057        InputPair,
2058        &mut Alloc,
2059    ),
2060{
2061    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2062    if params.log_meta_block {
2063        LogMetaBlock(
2064            alloc,
2065            commands.split_at(n_commands).0,
2066            input0,
2067            input1,
2068            distance_cache,
2069            recoder_state,
2070            block_split_reference(mb),
2071            params,
2072            Some(literal_context_mode),
2073            callback,
2074        );
2075    }
2076    let mut pos: usize = start_pos;
2077    let num_distance_symbols = params.dist.alphabet_size;
2078    let mut num_effective_distance_symbols = num_distance_symbols as usize;
2079    let _literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
2080    let mut literal_enc: BlockEncoder<Alloc>;
2081    let mut command_enc: BlockEncoder<Alloc>;
2082    let mut distance_enc: BlockEncoder<Alloc>;
2083    let dist = &params.dist;
2084    if params.large_window && num_effective_distance_symbols > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
2085    {
2086        num_effective_distance_symbols = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS;
2087    }
2088    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2089    let mut tree = allocate::<HuffmanTree, _>(alloc, 2 * 704 + 1);
2090    literal_enc = BlockEncoder::new(
2091        BROTLI_NUM_LITERAL_SYMBOLS,
2092        mb.literal_split.num_types,
2093        mb.literal_split.types.slice(),
2094        mb.literal_split.lengths.slice(),
2095        mb.literal_split.num_blocks,
2096    );
2097    command_enc = BlockEncoder::new(
2098        BROTLI_NUM_COMMAND_SYMBOLS,
2099        mb.command_split.num_types,
2100        mb.command_split.types.slice(),
2101        mb.command_split.lengths.slice(),
2102        mb.command_split.num_blocks,
2103    );
2104    distance_enc = BlockEncoder::new(
2105        num_effective_distance_symbols,
2106        mb.distance_split.num_types,
2107        mb.distance_split.types.slice(),
2108        mb.distance_split.lengths.slice(),
2109        mb.distance_split.num_blocks,
2110    );
2111    literal_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2112    command_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2113    distance_enc.build_and_store_block_switch_entropy_codes(tree.slice_mut(), storage_ix, storage);
2114    BrotliWriteBits(2, dist.distance_postfix_bits as (u64), storage_ix, storage);
2115    BrotliWriteBits(
2116        4,
2117        (dist.num_direct_distance_codes >> dist.distance_postfix_bits) as (u64),
2118        storage_ix,
2119        storage,
2120    );
2121    for _i in 0usize..mb.literal_split.num_types {
2122        BrotliWriteBits(2, literal_context_mode as (u64), storage_ix, storage);
2123    }
2124    if mb.literal_context_map_size == 0usize {
2125        StoreTrivialContextMap(
2126            mb.literal_histograms_size,
2127            6,
2128            tree.slice_mut(),
2129            storage_ix,
2130            storage,
2131        );
2132    } else {
2133        EncodeContextMap(
2134            alloc,
2135            mb.literal_context_map.slice(),
2136            mb.literal_context_map_size,
2137            mb.literal_histograms_size,
2138            tree.slice_mut(),
2139            storage_ix,
2140            storage,
2141        );
2142    }
2143    if mb.distance_context_map_size == 0usize {
2144        StoreTrivialContextMap(
2145            mb.distance_histograms_size,
2146            2usize,
2147            tree.slice_mut(),
2148            storage_ix,
2149            storage,
2150        );
2151    } else {
2152        EncodeContextMap(
2153            alloc,
2154            mb.distance_context_map.slice(),
2155            mb.distance_context_map_size,
2156            mb.distance_histograms_size,
2157            tree.slice_mut(),
2158            storage_ix,
2159            storage,
2160        );
2161    }
2162    literal_enc.build_and_store_entropy_codes(
2163        alloc,
2164        mb.literal_histograms.slice(),
2165        mb.literal_histograms_size,
2166        BROTLI_NUM_LITERAL_SYMBOLS,
2167        tree.slice_mut(),
2168        storage_ix,
2169        storage,
2170    );
2171    command_enc.build_and_store_entropy_codes(
2172        alloc,
2173        mb.command_histograms.slice(),
2174        mb.command_histograms_size,
2175        BROTLI_NUM_COMMAND_SYMBOLS,
2176        tree.slice_mut(),
2177        storage_ix,
2178        storage,
2179    );
2180    distance_enc.build_and_store_entropy_codes(
2181        alloc,
2182        mb.distance_histograms.slice(),
2183        mb.distance_histograms_size,
2184        num_distance_symbols as usize,
2185        tree.slice_mut(),
2186        storage_ix,
2187        storage,
2188    );
2189    {
2190        <Alloc as Allocator<HuffmanTree>>::free_cell(alloc, core::mem::take(&mut tree));
2191    }
2192    for i in 0usize..n_commands {
2193        let cmd: Command = commands[i];
2194        let cmd_code: usize = cmd.cmd_prefix_ as usize;
2195        command_enc.store_symbol(cmd_code, storage_ix, storage);
2196        StoreCommandExtra(&cmd, storage_ix, storage);
2197        if mb.literal_context_map_size == 0usize {
2198            let mut j: usize;
2199            j = cmd.insert_len_ as usize;
2200            while j != 0usize {
2201                {
2202                    literal_enc.store_symbol(input[(pos & mask)] as usize, storage_ix, storage);
2203                    pos = pos.wrapping_add(1);
2204                }
2205                j = j.wrapping_sub(1);
2206            }
2207        } else {
2208            let mut j: usize;
2209            j = cmd.insert_len_ as usize;
2210            while j != 0usize {
2211                {
2212                    let context: usize =
2213                        Context(prev_byte, prev_byte2, literal_context_mode) as usize;
2214                    let literal: u8 = input[(pos & mask)];
2215                    literal_enc.store_symbol_with_context(
2216                        literal as usize,
2217                        context,
2218                        mb.literal_context_map.slice(),
2219                        storage_ix,
2220                        storage,
2221                        6usize,
2222                    );
2223                    prev_byte2 = prev_byte;
2224                    prev_byte = literal;
2225                    pos = pos.wrapping_add(1);
2226                }
2227                j = j.wrapping_sub(1);
2228            }
2229        }
2230        pos = pos.wrapping_add(cmd.copy_len() as usize);
2231        if cmd.copy_len() != 0 {
2232            prev_byte2 = input[(pos.wrapping_sub(2) & mask)];
2233            prev_byte = input[(pos.wrapping_sub(1) & mask)];
2234            if cmd.cmd_prefix_ as i32 >= 128i32 {
2235                let dist_code: usize = cmd.dist_prefix_ as usize & 0x03ff;
2236                let distnumextra: u32 = u32::from(cmd.dist_prefix_) >> 10; //FIXME: from command
2237                let distextra: u64 = cmd.dist_extra_ as (u64);
2238                if mb.distance_context_map_size == 0usize {
2239                    distance_enc.store_symbol(dist_code, storage_ix, storage);
2240                } else {
2241                    distance_enc.store_symbol_with_context(
2242                        dist_code,
2243                        cmd.distance_context() as usize,
2244                        mb.distance_context_map.slice(),
2245                        storage_ix,
2246                        storage,
2247                        2usize,
2248                    );
2249                }
2250                BrotliWriteBits(distnumextra as u8, distextra, storage_ix, storage);
2251            }
2252        }
2253    }
2254    distance_enc.cleanup(alloc);
2255    command_enc.cleanup(alloc);
2256    literal_enc.cleanup(alloc);
2257    if is_last {
2258        JumpToByteBoundary(storage_ix, storage);
2259    }
2260}
2261
2262fn BuildHistograms(
2263    input: &[u8],
2264    start_pos: usize,
2265    mask: usize,
2266    commands: &[Command],
2267    n_commands: usize,
2268    lit_histo: &mut HistogramLiteral,
2269    cmd_histo: &mut HistogramCommand,
2270    dist_histo: &mut HistogramDistance,
2271) {
2272    let mut pos: usize = start_pos;
2273    for i in 0usize..n_commands {
2274        let cmd: Command = commands[i];
2275        let mut j: usize;
2276        HistogramAddItem(cmd_histo, cmd.cmd_prefix_ as usize);
2277        j = cmd.insert_len_ as usize;
2278        while j != 0usize {
2279            {
2280                HistogramAddItem(lit_histo, input[(pos & mask)] as usize);
2281                pos = pos.wrapping_add(1);
2282            }
2283            j = j.wrapping_sub(1);
2284        }
2285        pos = pos.wrapping_add(cmd.copy_len() as usize);
2286        if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
2287            HistogramAddItem(dist_histo, cmd.dist_prefix_ as usize & 0x03ff);
2288        }
2289    }
2290}
2291fn StoreDataWithHuffmanCodes(
2292    input: &[u8],
2293    start_pos: usize,
2294    mask: usize,
2295    commands: &[Command],
2296    n_commands: usize,
2297    lit_depth: &[u8],
2298    lit_bits: &[u16],
2299    cmd_depth: &[u8],
2300    cmd_bits: &[u16],
2301    dist_depth: &[u8],
2302    dist_bits: &[u16],
2303    storage_ix: &mut usize,
2304    storage: &mut [u8],
2305) {
2306    let mut pos: usize = start_pos;
2307    for i in 0usize..n_commands {
2308        let cmd: Command = commands[i];
2309        let cmd_code: usize = cmd.cmd_prefix_ as usize;
2310        let mut j: usize;
2311        BrotliWriteBits(
2312            cmd_depth[cmd_code],
2313            cmd_bits[cmd_code] as (u64),
2314            storage_ix,
2315            storage,
2316        );
2317        StoreCommandExtra(&cmd, storage_ix, storage);
2318        j = cmd.insert_len_ as usize;
2319        while j != 0usize {
2320            {
2321                let literal: u8 = input[(pos & mask)];
2322                BrotliWriteBits(
2323                    lit_depth[(literal as usize)],
2324                    lit_bits[(literal as usize)] as (u64),
2325                    storage_ix,
2326                    storage,
2327                );
2328                pos = pos.wrapping_add(1);
2329            }
2330            j = j.wrapping_sub(1);
2331        }
2332        pos = pos.wrapping_add(cmd.copy_len() as usize);
2333        if cmd.copy_len() != 0 && cmd.cmd_prefix_ >= 128 {
2334            let dist_code: usize = cmd.dist_prefix_ as usize & 0x03ff;
2335            let distnumextra: u32 = u32::from(cmd.dist_prefix_) >> 10;
2336            let distextra: u32 = cmd.dist_extra_;
2337            BrotliWriteBits(
2338                dist_depth[dist_code],
2339                dist_bits[dist_code] as (u64),
2340                storage_ix,
2341                storage,
2342            );
2343            BrotliWriteBits(distnumextra as u8, distextra as (u64), storage_ix, storage);
2344        }
2345    }
2346}
2347
2348#[cfg_attr(feature = "hotpath", hotpath::measure)]
2349pub(crate) fn store_meta_block_trivial<Alloc: BrotliAlloc, Cb>(
2350    alloc: &mut Alloc,
2351    input: &[u8],
2352    start_pos: usize,
2353    length: usize,
2354    mask: usize,
2355    is_last: bool,
2356    params: &BrotliEncoderParams,
2357    distance_cache: &[i32; kNumDistanceCacheEntries],
2358    commands: &[Command],
2359    n_commands: usize,
2360    recoder_state: &mut RecoderState,
2361    storage_ix: &mut usize,
2362    storage: &mut [u8],
2363    f: &mut Cb,
2364) where
2365    Cb: FnMut(
2366        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2367        &mut [interface::StaticCommand],
2368        InputPair,
2369        &mut Alloc,
2370    ),
2371{
2372    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2373    if params.log_meta_block {
2374        LogMetaBlock(
2375            alloc,
2376            commands.split_at(n_commands).0,
2377            input0,
2378            input1,
2379            distance_cache,
2380            recoder_state,
2381            block_split_nop(),
2382            params,
2383            Some(ContextType::CONTEXT_LSB6),
2384            f,
2385        );
2386    }
2387    let mut lit_histo: HistogramLiteral = HistogramLiteral::default();
2388    let mut cmd_histo: HistogramCommand = HistogramCommand::default();
2389    let mut dist_histo: HistogramDistance = HistogramDistance::default();
2390    let mut lit_depth: [u8; 256] = [0; 256];
2391    let mut lit_bits: [u16; 256] = [0; 256];
2392    let mut cmd_depth: [u8; 704] = [0; 704];
2393    let mut cmd_bits: [u16; 704] = [0; 704];
2394    let mut dist_depth: [u8; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2395        [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2396    let mut dist_bits: [u16; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2397        [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2398    const MAX_HUFFMAN_TREE_SIZE: usize = (2i32 * 704i32 + 1i32) as usize;
2399    let mut tree: [HuffmanTree; MAX_HUFFMAN_TREE_SIZE] = [HuffmanTree {
2400        total_count_: 0,
2401        index_left_: 0,
2402        index_right_or_value_: 0,
2403    }; MAX_HUFFMAN_TREE_SIZE];
2404    let num_distance_symbols = params.dist.alphabet_size;
2405    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2406    BuildHistograms(
2407        input,
2408        start_pos,
2409        mask,
2410        commands,
2411        n_commands,
2412        &mut lit_histo,
2413        &mut cmd_histo,
2414        &mut dist_histo,
2415    );
2416    BrotliWriteBits(13, 0, storage_ix, storage);
2417    BuildAndStoreHuffmanTree(
2418        lit_histo.slice_mut(),
2419        BROTLI_NUM_LITERAL_SYMBOLS,
2420        BROTLI_NUM_LITERAL_SYMBOLS,
2421        &mut tree[..],
2422        &mut lit_depth[..],
2423        &mut lit_bits[..],
2424        storage_ix,
2425        storage,
2426    );
2427    BuildAndStoreHuffmanTree(
2428        cmd_histo.slice_mut(),
2429        BROTLI_NUM_COMMAND_SYMBOLS,
2430        BROTLI_NUM_COMMAND_SYMBOLS,
2431        &mut tree[..],
2432        &mut cmd_depth[..],
2433        &mut cmd_bits[..],
2434        storage_ix,
2435        storage,
2436    );
2437    BuildAndStoreHuffmanTree(
2438        dist_histo.slice_mut(),
2439        MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
2440        num_distance_symbols as usize,
2441        &mut tree[..],
2442        &mut dist_depth[..],
2443        &mut dist_bits[..],
2444        storage_ix,
2445        storage,
2446    );
2447    StoreDataWithHuffmanCodes(
2448        input,
2449        start_pos,
2450        mask,
2451        commands,
2452        n_commands,
2453        &mut lit_depth[..],
2454        &mut lit_bits[..],
2455        &mut cmd_depth[..],
2456        &mut cmd_bits[..],
2457        &mut dist_depth[..],
2458        &mut dist_bits[..],
2459        storage_ix,
2460        storage,
2461    );
2462    if is_last {
2463        JumpToByteBoundary(storage_ix, storage);
2464    }
2465}
2466
2467fn StoreStaticCommandHuffmanTree(storage_ix: &mut usize, storage: &mut [u8]) {
2468    BrotliWriteBits(56, 0x0092_6244_1630_7003, storage_ix, storage);
2469    BrotliWriteBits(3, 0, storage_ix, storage);
2470}
2471
2472fn StoreStaticDistanceHuffmanTree(storage_ix: &mut usize, storage: &mut [u8]) {
2473    BrotliWriteBits(28, 0x0369_dc03, storage_ix, storage);
2474}
2475
2476struct BlockSplitRef<'a> {
2477    types: &'a [u8],
2478    lengths: &'a [u32],
2479    num_types: u32,
2480}
2481
2482impl<'a> Default for BlockSplitRef<'a> {
2483    fn default() -> Self {
2484        BlockSplitRef {
2485            types: &[],
2486            lengths: &[],
2487            num_types: 1,
2488        }
2489    }
2490}
2491
2492#[derive(Default)]
2493struct MetaBlockSplitRefs<'a> {
2494    btypel: BlockSplitRef<'a>,
2495    literal_context_map: &'a [u32],
2496    btypec: BlockSplitRef<'a>,
2497    btyped: BlockSplitRef<'a>,
2498    distance_context_map: &'a [u32],
2499}
2500
2501fn block_split_nop() -> MetaBlockSplitRefs<'static> {
2502    MetaBlockSplitRefs::default()
2503}
2504
2505fn block_split_reference<'a, Alloc: BrotliAlloc>(
2506    mb: &'a MetaBlockSplit<Alloc>,
2507) -> MetaBlockSplitRefs<'a> {
2508    return MetaBlockSplitRefs::<'a> {
2509        btypel: BlockSplitRef {
2510            types: mb
2511                .literal_split
2512                .types
2513                .slice()
2514                .split_at(mb.literal_split.num_blocks)
2515                .0,
2516            lengths: mb
2517                .literal_split
2518                .lengths
2519                .slice()
2520                .split_at(mb.literal_split.num_blocks)
2521                .0,
2522            num_types: mb.literal_split.num_types as u32,
2523        },
2524        literal_context_map: mb
2525            .literal_context_map
2526            .slice()
2527            .split_at(mb.literal_context_map_size)
2528            .0,
2529        btypec: BlockSplitRef {
2530            types: mb
2531                .command_split
2532                .types
2533                .slice()
2534                .split_at(mb.command_split.num_blocks)
2535                .0,
2536            lengths: mb
2537                .command_split
2538                .lengths
2539                .slice()
2540                .split_at(mb.command_split.num_blocks)
2541                .0,
2542            num_types: mb.command_split.num_types as u32,
2543        },
2544        btyped: BlockSplitRef {
2545            types: mb
2546                .distance_split
2547                .types
2548                .slice()
2549                .split_at(mb.distance_split.num_blocks)
2550                .0,
2551            lengths: mb
2552                .distance_split
2553                .lengths
2554                .slice()
2555                .split_at(mb.distance_split.num_blocks)
2556                .0,
2557            num_types: mb.distance_split.num_types as u32,
2558        },
2559        distance_context_map: mb
2560            .distance_context_map
2561            .slice()
2562            .split_at(mb.distance_context_map_size)
2563            .0,
2564    };
2565}
2566
2567#[derive(Clone, Copy, Default)]
2568pub struct RecoderState {
2569    pub num_bytes_encoded: usize,
2570}
2571
2572impl RecoderState {
2573    pub fn new() -> Self {
2574        Self::default()
2575    }
2576}
2577
2578#[cfg_attr(feature = "hotpath", hotpath::measure)]
2579pub(crate) fn store_meta_block_fast<Cb, Alloc: BrotliAlloc>(
2580    m: &mut Alloc,
2581    input: &[u8],
2582    start_pos: usize,
2583    length: usize,
2584    mask: usize,
2585    is_last: bool,
2586    params: &BrotliEncoderParams,
2587    dist_cache: &[i32; kNumDistanceCacheEntries],
2588    commands: &[Command],
2589    n_commands: usize,
2590    recoder_state: &mut RecoderState,
2591    storage_ix: &mut usize,
2592    storage: &mut [u8],
2593    cb: &mut Cb,
2594) where
2595    Cb: FnMut(
2596        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2597        &mut [StaticCommand],
2598        InputPair,
2599        &mut Alloc,
2600    ),
2601{
2602    let (input0, input1) = InputPairFromMaskedInput(input, start_pos, length, mask);
2603    if params.log_meta_block {
2604        LogMetaBlock(
2605            m,
2606            commands.split_at(n_commands).0,
2607            input0,
2608            input1,
2609            dist_cache,
2610            recoder_state,
2611            block_split_nop(),
2612            params,
2613            Some(ContextType::CONTEXT_LSB6),
2614            cb,
2615        );
2616    }
2617    let num_distance_symbols = params.dist.alphabet_size;
2618    let distance_alphabet_bits = Log2FloorNonZero(u64::from(num_distance_symbols) - 1) + 1;
2619    StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
2620    BrotliWriteBits(13, 0, storage_ix, storage);
2621    if n_commands <= 128usize {
2622        let mut histogram: [u32; 256] = [0; 256];
2623        let mut pos: usize = start_pos;
2624        let mut num_literals: usize = 0usize;
2625        let mut lit_depth: [u8; 256] = [0; 256];
2626        let mut lit_bits: [u16; 256] = [0; 256];
2627        for i in 0usize..n_commands {
2628            let cmd: Command = commands[i];
2629            let mut j: usize;
2630            j = cmd.insert_len_ as usize;
2631            while j != 0usize {
2632                {
2633                    {
2634                        let _rhs = 1;
2635                        let _lhs = &mut histogram[input[(pos & mask)] as usize];
2636                        *_lhs = (*_lhs).wrapping_add(_rhs as u32);
2637                    }
2638                    pos = pos.wrapping_add(1);
2639                }
2640                j = j.wrapping_sub(1);
2641            }
2642            num_literals = num_literals.wrapping_add(cmd.insert_len_ as usize);
2643            pos = pos.wrapping_add(cmd.copy_len() as usize);
2644        }
2645        BrotliBuildAndStoreHuffmanTreeFast(
2646            m,
2647            &mut histogram[..],
2648            num_literals,
2649            8usize,
2650            &mut lit_depth[..],
2651            &mut lit_bits[..],
2652            storage_ix,
2653            storage,
2654        );
2655        StoreStaticCommandHuffmanTree(storage_ix, storage);
2656        StoreStaticDistanceHuffmanTree(storage_ix, storage);
2657        StoreDataWithHuffmanCodes(
2658            input,
2659            start_pos,
2660            mask,
2661            commands,
2662            n_commands,
2663            &mut lit_depth[..],
2664            &mut lit_bits[..],
2665            &kStaticCommandCodeDepth[..],
2666            &kStaticCommandCodeBits[..],
2667            &kStaticDistanceCodeDepth[..],
2668            &kStaticDistanceCodeBits[..],
2669            storage_ix,
2670            storage,
2671        );
2672    } else {
2673        let mut lit_histo: HistogramLiteral = HistogramLiteral::default();
2674        let mut cmd_histo: HistogramCommand = HistogramCommand::default();
2675        let mut dist_histo: HistogramDistance = HistogramDistance::default();
2676        let mut lit_depth: [u8; 256] = [0; 256];
2677        let mut lit_bits: [u16; 256] = [0; 256];
2678        let mut cmd_depth: [u8; 704] = [0; 704];
2679        let mut cmd_bits: [u16; 704] = [0; 704];
2680        let mut dist_depth: [u8; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2681            [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2682        let mut dist_bits: [u16; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE] =
2683            [0; MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
2684        BuildHistograms(
2685            input,
2686            start_pos,
2687            mask,
2688            commands,
2689            n_commands,
2690            &mut lit_histo,
2691            &mut cmd_histo,
2692            &mut dist_histo,
2693        );
2694        BrotliBuildAndStoreHuffmanTreeFast(
2695            m,
2696            lit_histo.slice(),
2697            lit_histo.total_count_,
2698            8usize,
2699            &mut lit_depth[..],
2700            &mut lit_bits[..],
2701            storage_ix,
2702            storage,
2703        );
2704        BrotliBuildAndStoreHuffmanTreeFast(
2705            m,
2706            cmd_histo.slice(),
2707            cmd_histo.total_count_,
2708            10usize,
2709            &mut cmd_depth[..],
2710            &mut cmd_bits[..],
2711            storage_ix,
2712            storage,
2713        );
2714        BrotliBuildAndStoreHuffmanTreeFast(
2715            m,
2716            dist_histo.slice(),
2717            dist_histo.total_count_,
2718            distance_alphabet_bits as usize,
2719            &mut dist_depth[..],
2720            &mut dist_bits[..],
2721            storage_ix,
2722            storage,
2723        );
2724        StoreDataWithHuffmanCodes(
2725            input,
2726            start_pos,
2727            mask,
2728            commands,
2729            n_commands,
2730            &mut lit_depth[..],
2731            &mut lit_bits[..],
2732            &mut cmd_depth[..],
2733            &mut cmd_bits[..],
2734            &mut dist_depth[..],
2735            &mut dist_bits[..],
2736            storage_ix,
2737            storage,
2738        );
2739    }
2740    if is_last {
2741        JumpToByteBoundary(storage_ix, storage);
2742    }
2743}
2744fn BrotliStoreUncompressedMetaBlockHeader(
2745    length: usize,
2746    storage_ix: &mut usize,
2747    storage: &mut [u8],
2748) {
2749    let mut lenbits: u64 = 0;
2750    let mut nlenbits: u32 = 0;
2751    let mut nibblesbits: u32 = 0;
2752    BrotliWriteBits(1, 0, storage_ix, storage);
2753    BrotliEncodeMlen(length as u32, &mut lenbits, &mut nlenbits, &mut nibblesbits);
2754    BrotliWriteBits(2, nibblesbits as u64, storage_ix, storage);
2755    BrotliWriteBits(nlenbits as u8, lenbits, storage_ix, storage);
2756    BrotliWriteBits(1, 1, storage_ix, storage);
2757}
2758
2759fn InputPairFromMaskedInput(
2760    input: &[u8],
2761    position: usize,
2762    len: usize,
2763    mask: usize,
2764) -> (&[u8], &[u8]) {
2765    let masked_pos: usize = position & mask;
2766    if masked_pos.wrapping_add(len) > mask.wrapping_add(1) {
2767        let len1: usize = mask.wrapping_add(1).wrapping_sub(masked_pos);
2768        return (
2769            &input[masked_pos..(masked_pos + len1)],
2770            &input[0..len.wrapping_sub(len1)],
2771        );
2772    }
2773    (&input[masked_pos..masked_pos + len], &[])
2774}
2775
2776pub(crate) fn store_uncompressed_meta_block<Cb, Alloc: BrotliAlloc>(
2777    alloc: &mut Alloc,
2778    is_final_block: bool,
2779    input: &[u8],
2780    position: usize,
2781    mask: usize,
2782    params: &BrotliEncoderParams,
2783    len: usize,
2784    recoder_state: &mut RecoderState,
2785    storage_ix: &mut usize,
2786    storage: &mut [u8],
2787    suppress_meta_block_logging: bool,
2788    cb: &mut Cb,
2789) where
2790    Cb: FnMut(
2791        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2792        &mut [StaticCommand],
2793        InputPair,
2794        &mut Alloc,
2795    ),
2796{
2797    let (input0, input1) = InputPairFromMaskedInput(input, position, len, mask);
2798    BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage);
2799    JumpToByteBoundary(storage_ix, storage);
2800    let dst_start0 = (*storage_ix >> 3);
2801    storage[dst_start0..(dst_start0 + input0.len())].clone_from_slice(input0);
2802    *storage_ix = storage_ix.wrapping_add(input0.len() << 3);
2803    let dst_start1 = (*storage_ix >> 3);
2804    storage[dst_start1..(dst_start1 + input1.len())].clone_from_slice(input1);
2805    *storage_ix = storage_ix.wrapping_add(input1.len() << 3);
2806    BrotliWriteBitsPrepareStorage(*storage_ix, storage);
2807    if params.log_meta_block && !suppress_meta_block_logging {
2808        let cmds = [Command {
2809            insert_len_: len as u32,
2810            copy_len_: 0,
2811            dist_extra_: 0,
2812            cmd_prefix_: 0,
2813            dist_prefix_: 0,
2814        }];
2815
2816        LogMetaBlock(
2817            alloc,
2818            &cmds,
2819            input0,
2820            input1,
2821            &[0, 0, 0, 0],
2822            recoder_state,
2823            block_split_nop(),
2824            params,
2825            None,
2826            cb,
2827        );
2828    }
2829    if is_final_block {
2830        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
2831        BrotliWriteBits(1u8, 1u64, storage_ix, storage);
2832        JumpToByteBoundary(storage_ix, storage);
2833    }
2834}
2835
2836pub fn BrotliStoreSyncMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2837    BrotliWriteBits(6, 6, storage_ix, storage);
2838    JumpToByteBoundary(storage_ix, storage);
2839}
2840
2841pub fn BrotliWritePaddingMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2842    if *storage_ix & 7 != 0 {
2843        BrotliWriteBits(6, 6, storage_ix, storage);
2844        JumpToByteBoundary(storage_ix, storage);
2845    }
2846}
2847
2848pub fn BrotliWriteEmptyLastMetaBlock(storage_ix: &mut usize, storage: &mut [u8]) {
2849    BrotliWriteBits(1, 1, storage_ix, storage);
2850    BrotliWriteBits(1, 1, storage_ix, storage);
2851    JumpToByteBoundary(storage_ix, storage);
2852}
2853
2854const MAX_SIZE_ENCODING: usize = 10;
2855
2856fn encode_base_128(mut value: u64) -> (usize, [u8; MAX_SIZE_ENCODING]) {
2857    let mut ret = [0u8; MAX_SIZE_ENCODING];
2858    for index in 0..ret.len() {
2859        ret[index] = (value & 0x7f) as u8;
2860        value >>= 7;
2861        if value != 0 {
2862            ret[index] |= 0x80;
2863        } else {
2864            return (index + 1, ret);
2865        }
2866    }
2867    (ret.len(), ret)
2868}
2869
2870pub fn BrotliWriteMetadataMetaBlock(
2871    params: &BrotliEncoderParams,
2872    storage_ix: &mut usize,
2873    storage: &mut [u8],
2874) {
2875    BrotliWriteBits(1u8, 0u64, storage_ix, storage); // not last
2876    BrotliWriteBits(2u8, 3u64, storage_ix, storage); // MNIBBLES = 0 (pattern 1,1)
2877    BrotliWriteBits(1u8, 0u64, storage_ix, storage); // reserved
2878    BrotliWriteBits(2u8, 1u64, storage_ix, storage); // num bytes for length of magic number header
2879    let (size_hint_count, size_hint_b128) = encode_base_128(params.size_hint as u64);
2880
2881    BrotliWriteBits(8u8, 3 + size_hint_count as u64, storage_ix, storage); // 1 byte of data: writing 12 for the magic number header
2882    JumpToByteBoundary(storage_ix, storage);
2883    let magic_number: [u8; 3] = if params.catable && !params.use_dictionary {
2884        [0xe1, 0x97, 0x81]
2885    } else if params.appendable {
2886        [0xe1, 0x97, 0x82]
2887    } else {
2888        [0xe1, 0x97, 0x80]
2889    };
2890    for magic in magic_number.iter() {
2891        BrotliWriteBits(8u8, u64::from(*magic), storage_ix, storage);
2892    }
2893    BrotliWriteBits(8u8, u64::from(VERSION), storage_ix, storage);
2894    for sh in size_hint_b128[..size_hint_count].iter() {
2895        BrotliWriteBits(8u8, u64::from(*sh), storage_ix, storage);
2896    }
2897}
2898
2899#[cfg(test)]
2900mod test {
2901    use crate::enc::brotli_bit_stream::{MAX_SIZE_ENCODING, encode_base_128};
2902
2903    #[test]
2904    fn test_encode_base_128() {
2905        assert_eq!(encode_base_128(0), (1, [0u8; MAX_SIZE_ENCODING]));
2906        assert_eq!(encode_base_128(1), (1, [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
2907        assert_eq!(encode_base_128(127), (1, [0x7f, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
2908        assert_eq!(
2909            encode_base_128(128),
2910            (2, [0x80, 0x1, 0, 0, 0, 0, 0, 0, 0, 0])
2911        );
2912        assert_eq!(
2913            encode_base_128(16383),
2914            (2, [0xff, 0x7f, 0, 0, 0, 0, 0, 0, 0, 0])
2915        );
2916        assert_eq!(
2917            encode_base_128(16384),
2918            (3, [0x80, 0x80, 0x1, 0, 0, 0, 0, 0, 0, 0])
2919        );
2920        assert_eq!(
2921            encode_base_128(2097151),
2922            (3, [0xff, 0xff, 0x7f, 0, 0, 0, 0, 0, 0, 0])
2923        );
2924        assert_eq!(
2925            encode_base_128(2097152),
2926            (4, [0x80, 0x80, 0x80, 0x1, 0, 0, 0, 0, 0, 0])
2927        );
2928        assert_eq!(
2929            encode_base_128(4194303),
2930            (4, [0xff, 0xff, 0xff, 0x1, 0, 0, 0, 0, 0, 0])
2931        );
2932        assert_eq!(
2933            encode_base_128(4294967295),
2934            (5, [0xff, 0xff, 0xff, 0xff, 0xf, 0, 0, 0, 0, 0])
2935        );
2936        assert_eq!(
2937            encode_base_128(4294967296),
2938            (5, [0x80, 0x80, 0x80, 0x80, 0x10, 0, 0, 0, 0, 0])
2939        );
2940        assert_eq!(
2941            encode_base_128(9223372036854775808),
2942            (
2943                10,
2944                [0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x1]
2945            )
2946        );
2947        assert_eq!(
2948            encode_base_128(18446744073709551615),
2949            (
2950                10,
2951                [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1]
2952            )
2953        );
2954    }
2955}