brotli/enc/
encode.rs

1#![allow(dead_code)]
2use super::backward_references::{
3    AdvHashSpecialization, AdvHasher, AnyHasher, BasicHasher, BrotliCreateBackwardReferences,
4    BrotliEncoderMode, BrotliEncoderParams, BrotliHasherParams, H2Sub, H3Sub, H4Sub, H54Sub, H5Sub,
5    H6Sub, HQ5Sub, HQ7Sub, HowPrepared, StoreLookaheadThenStore, Struct1, UnionHasher, H9,
6    H9_BLOCK_BITS, H9_BLOCK_SIZE, H9_BUCKET_BITS, H9_NUM_LAST_DISTANCES_TO_CHECK,
7};
8use super::bit_cost::{BitsEntropy, ShannonEntropy};
9#[allow(unused_imports)]
10use super::block_split::BlockSplit;
11#[allow(unused_imports)]
12use super::brotli_bit_stream::{
13    BrotliBuildAndStoreHuffmanTreeFast, BrotliStoreHuffmanTree, BrotliStoreMetaBlock,
14    BrotliStoreMetaBlockFast, BrotliStoreMetaBlockTrivial, BrotliStoreUncompressedMetaBlock,
15    BrotliWriteEmptyLastMetaBlock, BrotliWriteMetadataMetaBlock, JumpToByteBoundary,
16    MetaBlockSplit, RecoderState,
17};
18use super::combined_alloc::BrotliAlloc;
19use super::constants::{
20    BROTLI_CONTEXT, BROTLI_CONTEXT_LUT, BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX,
21    BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS, BROTLI_WINDOW_GAP,
22};
23use super::hash_to_binary_tree::InitializeH10;
24use super::interface;
25pub use super::parameters::BrotliEncoderParameter;
26use alloc::Allocator;
27
28use super::super::alloc;
29use super::super::alloc::{SliceWrapper, SliceWrapperMut};
30use super::command::{BrotliDistanceParams, Command, GetLengthCode};
31use super::compress_fragment::BrotliCompressFragmentFast;
32use super::compress_fragment_two_pass::{BrotliCompressFragmentTwoPass, BrotliWriteBits};
33#[allow(unused_imports)]
34use super::entropy_encode::{
35    BrotliConvertBitDepthsToSymbols, BrotliCreateHuffmanTree, HuffmanTree,
36};
37use super::histogram::{
38    ContextType, CostAccessors, HistogramCommand, HistogramDistance, HistogramLiteral,
39};
40use super::metablock::{
41    BrotliBuildMetaBlock, BrotliBuildMetaBlockGreedy, BrotliInitDistanceParams,
42    BrotliOptimizeHistograms,
43};
44use super::static_dict::{kNumDistanceCacheEntries, BrotliGetDictionary};
45use super::utf8_util::BrotliIsMostlyUTF8;
46use super::util::{brotli_min_size_t, Log2FloorNonZero};
47use core;
48use enc::input_pair::InputReferenceMut;
49//fn BrotliCreateHqZopfliBackwardReferences(m: &mut [MemoryManager],
50//                                          dictionary: &[BrotliDictionary],
51//                                          num_bytes: usize,
52//                                          position: usize,
53//                                          ringbuffer: &[u8],
54//                                          ringbuffer_mask: usize,
55//                                          params: &[BrotliEncoderParams],
56//                                          hasher: &mut [u8],
57//                                          dist_cache: &mut [i32],
58//                                          last_insert_len: &mut [usize],
59//                                          commands: &mut [Command],
60//                                          num_commands: &mut [usize],
61//                                          num_literals: &mut [usize]);
62//fn BrotliCreateZopfliBackwardReferences(m: &mut [MemoryManager],
63//                                       dictionary: &[BrotliDictionary],
64//                                      num_bytes: usize,
65//                                        position: usize,
66//                                        ringbuffer: &[u8],
67//                                        ringbuffer_mask: usize,
68//                                        params: &[BrotliEncoderParams],
69//                                        hasher: &mut [u8],
70//                                        dist_cache: &mut [i32],
71//                                        last_insert_len: &mut [usize],
72//                                        commands: &mut [Command],
73//                                        num_commands: &mut [usize],
74//                                        num_literals: &mut [usize]);
75//fn BrotliInitBlockSplit(xself: &mut BlockSplit);
76//fn BrotliInitMemoryManager(m: &mut [MemoryManager],
77//                           alloc_func: fn(&mut [::std::os::raw::c_void], usize)
78//                                          -> *mut ::std::os::raw::c_void,
79//                           free_func: fn(*mut ::std::os::raw::c_void,
80//                                         *mut ::std::os::raw::c_void),
81//                           opaque: *mut ::std::os::raw::c_void);
82//fn BrotliInitZopfliNodes(array: &mut [ZopfliNode], length: usize);
83//fn BrotliWipeOutMemoryManager(m: &mut [MemoryManager]);
84
85static kCompressFragmentTwoPassBlockSize: usize = (1i32 << 17) as usize;
86
87static kMinUTF8Ratio: super::util::floatX = 0.75 as super::util::floatX;
88
89pub struct RingBuffer<AllocU8: alloc::Allocator<u8>> {
90    pub size_: u32,
91    pub mask_: u32,
92    pub tail_size_: u32,
93    pub total_size_: u32,
94    pub cur_size_: u32,
95    pub pos_: u32,
96    pub data_mo: AllocU8::AllocatedMemory,
97    pub buffer_index: usize,
98}
99
100#[derive(PartialEq, Eq, Copy, Clone)]
101#[repr(i32)]
102pub enum BrotliEncoderStreamState {
103    BROTLI_STREAM_PROCESSING = 0,
104    BROTLI_STREAM_FLUSH_REQUESTED = 1,
105    BROTLI_STREAM_FINISHED = 2,
106    BROTLI_STREAM_METADATA_HEAD = 3,
107    BROTLI_STREAM_METADATA_BODY = 4,
108}
109
110#[derive(Clone, Copy, Debug)]
111enum NextOut {
112    DynamicStorage(u32),
113    TinyBuf(u32),
114    None,
115}
116fn GetNextOutInternal<'a>(
117    next_out: &NextOut,
118    storage: &'a mut [u8],
119    tiny_buf: &'a mut [u8; 16],
120) -> &'a mut [u8] {
121    match next_out {
122        &NextOut::DynamicStorage(offset) => &mut storage[offset as usize..],
123        &NextOut::TinyBuf(offset) => &mut tiny_buf[offset as usize..],
124        &NextOut::None => &mut [],
125    }
126}
127macro_rules! GetNextOut {
128    ($s : expr) => {
129        GetNextOutInternal(&$s.next_out_, $s.storage_.slice_mut(), &mut $s.tiny_buf_)
130    };
131}
132fn NextOutIncrement(next_out: &NextOut, inc: i32) -> NextOut {
133    match next_out {
134        &NextOut::DynamicStorage(offset) => NextOut::DynamicStorage((offset as i32 + inc) as u32),
135        &NextOut::TinyBuf(offset) => NextOut::TinyBuf((offset as i32 + inc) as u32),
136        &NextOut::None => NextOut::None,
137    }
138}
139fn IsNextOutNull(next_out: &NextOut) -> bool {
140    match next_out {
141        &NextOut::DynamicStorage(_) => false,
142        &NextOut::TinyBuf(_) => false,
143        &NextOut::None => true,
144    }
145}
146
147#[derive(Clone, Copy, Debug)]
148pub enum IsFirst {
149    NothingWritten,
150    HeaderWritten,
151    FirstCatableByteWritten,
152    BothCatableBytesWritten,
153}
154
155pub struct BrotliEncoderStateStruct<Alloc: BrotliAlloc> {
156    pub params: BrotliEncoderParams,
157    pub m8: Alloc,
158    pub hasher_: UnionHasher<Alloc>,
159    pub input_pos_: u64,
160    pub ringbuffer_: RingBuffer<Alloc>,
161    pub cmd_alloc_size_: usize,
162    pub commands_: <Alloc as Allocator<Command>>::AllocatedMemory, // not sure about this one
163    pub num_commands_: usize,
164    pub num_literals_: usize,
165    pub last_insert_len_: usize,
166    pub last_flush_pos_: u64,
167    pub last_processed_pos_: u64,
168    pub dist_cache_: [i32; 16],
169    pub saved_dist_cache_: [i32; kNumDistanceCacheEntries],
170    pub last_bytes_: u16,
171    pub last_bytes_bits_: u8,
172    pub prev_byte_: u8,
173    pub prev_byte2_: u8,
174    pub storage_size_: usize,
175    pub storage_: <Alloc as Allocator<u8>>::AllocatedMemory,
176    pub small_table_: [i32; 1024],
177    pub large_table_: <Alloc as Allocator<i32>>::AllocatedMemory,
178    //  pub large_table_size_: usize, // <-- get this by doing large_table_.len()
179    pub cmd_depths_: [u8; 128],
180    pub cmd_bits_: [u16; 128],
181    pub cmd_code_: [u8; 512],
182    pub cmd_code_numbits_: usize,
183    pub command_buf_: <Alloc as Allocator<u32>>::AllocatedMemory,
184    pub literal_buf_: <Alloc as Allocator<u8>>::AllocatedMemory,
185    next_out_: NextOut,
186    pub available_out_: usize,
187    pub total_out_: u64,
188    pub tiny_buf_: [u8; 16],
189    pub remaining_metadata_bytes_: u32,
190    pub stream_state_: BrotliEncoderStreamState,
191    pub is_last_block_emitted_: bool,
192    pub is_initialized_: bool,
193    pub is_first_mb: IsFirst,
194    pub literal_scratch_space: <HistogramLiteral as CostAccessors>::i32vec,
195    pub command_scratch_space: <HistogramCommand as CostAccessors>::i32vec,
196    pub distance_scratch_space: <HistogramDistance as CostAccessors>::i32vec,
197    pub recoder_state: RecoderState,
198    custom_dictionary: bool,
199}
200
201pub fn set_parameter(
202    params: &mut BrotliEncoderParams,
203    p: BrotliEncoderParameter,
204    value: u32,
205) -> i32 {
206    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_MODE as i32 {
207        params.mode = match value {
208            0 => BrotliEncoderMode::BROTLI_MODE_GENERIC,
209            1 => BrotliEncoderMode::BROTLI_MODE_TEXT,
210            2 => BrotliEncoderMode::BROTLI_MODE_FONT,
211            3 => BrotliEncoderMode::BROTLI_FORCE_LSB_PRIOR,
212            4 => BrotliEncoderMode::BROTLI_FORCE_MSB_PRIOR,
213            5 => BrotliEncoderMode::BROTLI_FORCE_UTF8_PRIOR,
214            6 => BrotliEncoderMode::BROTLI_FORCE_SIGNED_PRIOR,
215            _ => BrotliEncoderMode::BROTLI_MODE_GENERIC,
216        };
217        return 1i32;
218    }
219    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_QUALITY as i32 {
220        params.quality = value as i32;
221        return 1i32;
222    }
223    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_STRIDE_DETECTION_QUALITY as i32 {
224        params.stride_detection_quality = value as u8;
225        return 1i32;
226    }
227    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_HIGH_ENTROPY_DETECTION_QUALITY as i32 {
228        params.high_entropy_detection_quality = value as u8;
229        return 1i32;
230    }
231    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CDF_ADAPTATION_DETECTION as i32 {
232        params.cdf_adaptation_detection = value as u8;
233        return 1i32;
234    }
235    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_Q9_5 as i32 {
236        params.q9_5 = (value != 0);
237        return 1i32;
238    }
239    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_PRIOR_BITMASK_DETECTION as i32 {
240        params.prior_bitmask_detection = value as u8;
241        return 1i32;
242    }
243    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_SPEED as i32 {
244        params.literal_adaptation[1].0 = value as u16;
245        if params.literal_adaptation[0] == (0, 0) {
246            params.literal_adaptation[0].0 = value as u16;
247        }
248        return 1i32;
249    }
250    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_SPEED_MAX as i32 {
251        params.literal_adaptation[1].1 = value as u16;
252        if params.literal_adaptation[0].1 == 0 {
253            params.literal_adaptation[0].1 = value as u16;
254        }
255        return 1i32;
256    }
257    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CM_SPEED as i32 {
258        params.literal_adaptation[3].0 = value as u16;
259        if params.literal_adaptation[2] == (0, 0) {
260            params.literal_adaptation[2].0 = value as u16;
261        }
262        return 1i32;
263    }
264    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CM_SPEED_MAX as i32 {
265        params.literal_adaptation[3].1 = value as u16;
266        if params.literal_adaptation[2].1 == 0 {
267            params.literal_adaptation[2].1 = value as u16;
268        }
269        return 1i32;
270    }
271    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_SPEED_LOW as i32 {
272        params.literal_adaptation[0].0 = value as u16;
273        return 1i32;
274    }
275    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_SPEED_LOW_MAX as i32 {
276        params.literal_adaptation[0].1 = value as u16;
277        return 1i32;
278    }
279    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CM_SPEED_LOW as i32 {
280        params.literal_adaptation[2].0 = value as u16;
281        return 1i32;
282    }
283    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CM_SPEED_LOW_MAX as i32 {
284        params.literal_adaptation[2].1 = value as u16;
285        return 1i32;
286    }
287    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_LITERAL_BYTE_SCORE as i32 {
288        params.hasher.literal_byte_score = value as i32;
289        return 1i32;
290    }
291    if p as i32 == BrotliEncoderParameter::BROTLI_METABLOCK_CALLBACK as i32 {
292        params.log_meta_block = value != 0;
293        return 1i32;
294    }
295    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_LGWIN as i32 {
296        params.lgwin = value as i32;
297        return 1i32;
298    }
299    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_LGBLOCK as i32 {
300        params.lgblock = value as i32;
301        return 1i32;
302    }
303    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING as i32 {
304        if value != 0u32 && (value != 1u32) {
305            return 0i32;
306        }
307        params.disable_literal_context_modeling = if value != 0 { 1i32 } else { 0i32 };
308        return 1i32;
309    }
310    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_SIZE_HINT as i32 {
311        params.size_hint = value as usize;
312        return 1i32;
313    }
314    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_LARGE_WINDOW as i32 {
315        params.large_window = value != 0;
316        return 1i32;
317    }
318    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_AVOID_DISTANCE_PREFIX_SEARCH as i32 {
319        params.avoid_distance_prefix_search = value != 0;
320        return 1i32;
321    }
322    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_CATABLE as i32 {
323        params.catable = value != 0;
324        if !params.appendable {
325            params.appendable = value != 0;
326        }
327        params.use_dictionary = (value == 0);
328        return 1i32;
329    }
330    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_APPENDABLE as i32 {
331        params.appendable = value != 0;
332        return 1i32;
333    }
334    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_MAGIC_NUMBER as i32 {
335        params.magic_number = value != 0;
336        return 1i32;
337    }
338    if p as i32 == BrotliEncoderParameter::BROTLI_PARAM_FAVOR_EFFICIENCY as i32 {
339        params.favor_cpu_efficiency = value != 0;
340        return 1i32;
341    }
342    0i32
343}
344
345pub fn BrotliEncoderSetParameter<Alloc: BrotliAlloc>(
346    state: &mut BrotliEncoderStateStruct<Alloc>,
347    p: BrotliEncoderParameter,
348    value: u32,
349) -> i32 {
350    if state.is_initialized_ {
351        return 0i32;
352    }
353    set_parameter(&mut state.params, p, value)
354}
355/* "Large Window Brotli" */
356pub const BROTLI_LARGE_MAX_DISTANCE_BITS: u32 = 62;
357pub const BROTLI_LARGE_MIN_WBITS: u32 = 10;
358pub const BROTLI_LARGE_MAX_WBITS: u32 = 30;
359
360pub const BROTLI_MAX_DISTANCE_BITS: u32 = 24;
361pub const BROTLI_MAX_WINDOW_BITS: usize = BROTLI_MAX_DISTANCE_BITS as usize;
362pub const BROTLI_MAX_DISTANCE: usize = 0x3FFFFFC;
363pub const BROTLI_MAX_ALLOWED_DISTANCE: usize = 0x7FFFFFC;
364pub const BROTLI_NUM_DISTANCE_SHORT_CODES: u32 = 16;
365pub fn BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX: u32, NDIRECT: u32, MAXNBITS: u32) -> u32 {
366    BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + ((MAXNBITS) << ((NPOSTFIX) + 1))
367}
368
369//#define BROTLI_NUM_DISTANCE_SYMBOLS \
370//    BROTLI_DISTANCE_ALPHABET_SIZE(  \
371//        BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
372
373pub const BROTLI_NUM_DISTANCE_SYMBOLS: usize = 1128;
374
375pub fn BrotliEncoderInitParams() -> BrotliEncoderParams {
376    BrotliEncoderParams {
377        dist: BrotliDistanceParams {
378            distance_postfix_bits: 0,
379            num_direct_distance_codes: 0,
380            alphabet_size: BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS),
381            max_distance: BROTLI_MAX_DISTANCE,
382        },
383        mode: BrotliEncoderMode::BROTLI_MODE_GENERIC,
384        log_meta_block: false,
385        large_window: false,
386        avoid_distance_prefix_search: false,
387        quality: 11,
388        q9_5: false,
389        lgwin: 22i32,
390        lgblock: 0i32,
391        size_hint: 0usize,
392        disable_literal_context_modeling: 0i32,
393        stride_detection_quality: 0,
394        high_entropy_detection_quality: 0,
395        cdf_adaptation_detection: 0,
396        prior_bitmask_detection: 0,
397        literal_adaptation: [(0, 0); 4],
398        catable: false,
399        use_dictionary: true,
400        appendable: false,
401        magic_number: false,
402        favor_cpu_efficiency: false,
403        hasher: BrotliHasherParams {
404            type_: 6,
405            block_bits: 9 - 1,
406            bucket_bits: 15,
407            hash_len: 5,
408            num_last_distances_to_check: 16,
409            literal_byte_score: 0,
410        },
411    }
412}
413
414fn ExtendLastCommand<Alloc: BrotliAlloc>(
415    s: &mut BrotliEncoderStateStruct<Alloc>,
416    bytes: &mut u32,
417    wrapped_last_processed_pos: &mut u32,
418) {
419    let last_command = &mut s.commands_.slice_mut()[s.num_commands_ - 1];
420
421    let mask = s.ringbuffer_.mask_;
422    let max_backward_distance: u64 = (1u64 << s.params.lgwin) - BROTLI_WINDOW_GAP as u64;
423    let last_copy_len = u64::from(last_command.copy_len_) & 0x1ffffff;
424    let last_processed_pos: u64 = s.last_processed_pos_ - last_copy_len;
425    let max_distance: u64 = if last_processed_pos < max_backward_distance {
426        last_processed_pos
427    } else {
428        max_backward_distance
429    };
430    let cmd_dist: u64 = s.dist_cache_[0] as u64;
431    let distance_code: u32 =
432        super::command::CommandRestoreDistanceCode(last_command, &s.params.dist);
433    if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES
434        || distance_code as u64 - (BROTLI_NUM_DISTANCE_SHORT_CODES - 1) as u64 == cmd_dist)
435    {
436        if (cmd_dist <= max_distance) {
437            while (*bytes != 0
438                && s.ringbuffer_.data_mo.slice()[s.ringbuffer_.buffer_index
439                    + (*wrapped_last_processed_pos as usize & mask as usize)]
440                    == s.ringbuffer_.data_mo.slice()[s.ringbuffer_.buffer_index
441                        + (((*wrapped_last_processed_pos as usize)
442                            .wrapping_sub(cmd_dist as usize))
443                            & mask as usize)])
444            {
445                last_command.copy_len_ += 1;
446                (*bytes) -= 1;
447                (*wrapped_last_processed_pos) += 1;
448            }
449        }
450        /* The copy length is at most the metablock size, and thus expressible. */
451        GetLengthCode(
452            last_command.insert_len_ as usize,
453            ((last_command.copy_len_ & 0x1FFFFFF) as i32 + (last_command.copy_len_ >> 25) as i32)
454                as usize,
455            ((last_command.dist_prefix_ & 0x3FF) == 0) as i32,
456            &mut last_command.cmd_prefix_,
457        );
458    }
459}
460
461fn RingBufferInit<AllocU8: alloc::Allocator<u8>>() -> RingBuffer<AllocU8> {
462    RingBuffer {
463        size_: 0,
464        mask_: 0, // 0xff??
465        tail_size_: 0,
466        total_size_: 0,
467
468        cur_size_: 0,
469        pos_: 0,
470        data_mo: AllocU8::AllocatedMemory::default(),
471        buffer_index: 0usize,
472    }
473}
474
475pub fn BrotliEncoderCreateInstance<Alloc: BrotliAlloc>(
476    m8: Alloc,
477) -> BrotliEncoderStateStruct<Alloc> {
478    let cache: [i32; 16] = [4, 11, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
479    BrotliEncoderStateStruct::<Alloc> {
480        params: BrotliEncoderInitParams(),
481        input_pos_: 0,
482        num_commands_: 0usize,
483        num_literals_: 0usize,
484        last_insert_len_: 0usize,
485        last_flush_pos_: 0,
486        last_processed_pos_: 0,
487        prev_byte_: 0u8,
488        prev_byte2_: 0u8,
489        storage_size_: 0usize,
490        storage_: <Alloc as Allocator<u8>>::AllocatedMemory::default(),
491        hasher_: UnionHasher::<Alloc>::default(),
492        large_table_: <Alloc as Allocator<i32>>::AllocatedMemory::default(),
493        //    large_table_size_: 0usize,
494        cmd_code_numbits_: 0usize,
495        command_buf_: <Alloc as Allocator<u32>>::AllocatedMemory::default(),
496        literal_buf_: <Alloc as Allocator<u8>>::AllocatedMemory::default(),
497        next_out_: NextOut::None,
498        available_out_: 0usize,
499        total_out_: 0u64,
500        is_first_mb: IsFirst::NothingWritten,
501        stream_state_: BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING,
502        is_last_block_emitted_: false,
503        is_initialized_: false,
504        ringbuffer_: RingBufferInit(),
505        commands_: <Alloc as Allocator<Command>>::AllocatedMemory::default(),
506        cmd_alloc_size_: 0usize,
507        dist_cache_: cache,
508        saved_dist_cache_: [cache[0], cache[1], cache[2], cache[3]],
509        cmd_bits_: [0; 128],
510        cmd_depths_: [0; 128],
511        last_bytes_: 0,
512        last_bytes_bits_: 0,
513        cmd_code_: [0; 512],
514        m8,
515        remaining_metadata_bytes_: 0,
516        small_table_: [0; 1024],
517        tiny_buf_: [0; 16],
518        literal_scratch_space: HistogramLiteral::make_nnz_storage(),
519        command_scratch_space: HistogramCommand::make_nnz_storage(),
520        distance_scratch_space: HistogramDistance::make_nnz_storage(),
521        recoder_state: RecoderState::new(),
522        custom_dictionary: false,
523    }
524}
525
526fn RingBufferFree<AllocU8: alloc::Allocator<u8>>(m: &mut AllocU8, rb: &mut RingBuffer<AllocU8>) {
527    m.free_cell(core::mem::take(&mut rb.data_mo));
528}
529fn DestroyHasher<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
530    m16: &mut Alloc,
531    handle: &mut UnionHasher<Alloc>,
532) {
533    handle.free(m16);
534}
535/*
536fn DestroyHasher<AllocU16:alloc::Allocator<u16>, AllocU32:alloc::Allocator<u32>>(
537m16: &mut AllocU16, m32:&mut AllocU32, handle: &mut UnionHasher<AllocU16, AllocU32>){
538  match handle {
539    &mut UnionHasher::H2(ref mut hasher) => {
540        m32.free_cell(core::mem::replace(&mut hasher.buckets_.buckets_, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
541    }
542    &mut UnionHasher::H3(ref mut hasher) => {
543        m32.free_cell(core::mem::replace(&mut hasher.buckets_.buckets_, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
544    }
545    &mut UnionHasher::H4(ref mut hasher) => {
546        m32.free_cell(core::mem::replace(&mut hasher.buckets_.buckets_, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
547    }
548    &mut UnionHasher::H54(ref mut hasher) => {
549        m32.free_cell(core::mem::replace(&mut hasher.buckets_.buckets_, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
550    }
551    &mut UnionHasher::H5(ref mut hasher) => {
552      m16.free_cell(core::mem::replace(&mut hasher.num, AllocU16::AllocatedMemory::default()));
553      m32.free_cell(core::mem::replace(&mut hasher.buckets, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
554    }
555    &mut UnionHasher::H6(ref mut hasher) => {
556      m16.free_cell(core::mem::replace(&mut hasher.num, AllocU16::AllocatedMemory::default()));
557      m32.free_cell(core::mem::replace(&mut hasher.buckets, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
558    }
559    &mut UnionHasher::H9(ref mut hasher) => {
560      m16.free_cell(core::mem::replace(&mut hasher.num_, AllocU16::AllocatedMemory::default()));
561      m32.free_cell(core::mem::replace(&mut hasher.buckets_, <Alloc as Allocator<u32>>::AllocatedMemory::default()));
562    }
563    _ => {}
564  }
565  *handle = UnionHasher::<AllocU16, AllocU32>::default();
566}
567*/
568
569fn BrotliEncoderCleanupState<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) {
570    {
571        <Alloc as Allocator<u8>>::free_cell(&mut s.m8, core::mem::take(&mut s.storage_));
572    }
573    {
574        <Alloc as Allocator<Command>>::free_cell(&mut s.m8, core::mem::take(&mut s.commands_));
575    }
576    RingBufferFree(&mut s.m8, &mut s.ringbuffer_);
577    DestroyHasher(&mut s.m8, &mut s.hasher_);
578    {
579        <Alloc as Allocator<i32>>::free_cell(&mut s.m8, core::mem::take(&mut s.large_table_));
580    }
581    {
582        <Alloc as Allocator<u32>>::free_cell(&mut s.m8, core::mem::take(&mut s.command_buf_));
583    }
584    {
585        <Alloc as Allocator<u8>>::free_cell(&mut s.m8, core::mem::take(&mut s.literal_buf_));
586    }
587}
588
589pub fn BrotliEncoderDestroyInstance<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) {
590    BrotliEncoderCleanupState(s);
591}
592
593fn brotli_min_int(a: i32, b: i32) -> i32 {
594    if a < b {
595        a
596    } else {
597        b
598    }
599}
600
601fn brotli_max_int(a: i32, b: i32) -> i32 {
602    if a > b {
603        a
604    } else {
605        b
606    }
607}
608
609#[cfg(not(feature = "disallow_large_window_size"))]
610fn check_large_window_ok() -> bool {
611    true
612}
613#[cfg(feature = "disallow_large_window_size")]
614fn check_large_window_ok() -> bool {
615    false
616}
617
618pub fn SanitizeParams(params: &mut BrotliEncoderParams) {
619    params.quality = brotli_min_int(11i32, brotli_max_int(0i32, params.quality));
620    if params.lgwin < 10i32 {
621        params.lgwin = 10i32;
622    } else if params.lgwin > 24i32 {
623        if params.large_window && check_large_window_ok() {
624            if params.lgwin > 30i32 {
625                params.lgwin = 30i32;
626            }
627        } else {
628            params.lgwin = 24i32;
629        }
630    }
631    if params.catable {
632        params.appendable = true;
633    }
634}
635
636fn ComputeLgBlock(params: &BrotliEncoderParams) -> i32 {
637    let mut lgblock: i32 = params.lgblock;
638    if params.quality == 0i32 || params.quality == 1i32 {
639        lgblock = params.lgwin;
640    } else if params.quality < 4i32 {
641        lgblock = 14i32;
642    } else if lgblock == 0i32 {
643        lgblock = 16i32;
644        if params.quality >= 9i32 && (params.lgwin > lgblock) {
645            lgblock = brotli_min_int(18i32, params.lgwin);
646        }
647    } else {
648        lgblock = brotli_min_int(24i32, brotli_max_int(16i32, lgblock));
649    }
650    lgblock
651}
652
653fn ComputeRbBits(params: &BrotliEncoderParams) -> i32 {
654    1i32 + brotli_max_int(params.lgwin, params.lgblock)
655}
656
657fn RingBufferSetup<AllocU8: alloc::Allocator<u8>>(
658    params: &BrotliEncoderParams,
659    rb: &mut RingBuffer<AllocU8>,
660) {
661    let window_bits: i32 = ComputeRbBits(params);
662    let tail_bits: i32 = params.lgblock;
663    rb.size_ = 1u32 << window_bits;
664    rb.mask_ = (1u32 << window_bits).wrapping_sub(1);
665    rb.tail_size_ = 1u32 << tail_bits;
666    rb.total_size_ = rb.size_.wrapping_add(rb.tail_size_);
667}
668
669fn EncodeWindowBits(
670    lgwin: i32,
671    large_window: bool,
672    last_bytes: &mut u16,
673    last_bytes_bits: &mut u8,
674) {
675    if large_window {
676        *last_bytes = (((lgwin & 0x3F) << 8) | 0x11) as u16;
677        *last_bytes_bits = 14;
678    } else if lgwin == 16i32 {
679        *last_bytes = 0u16;
680        *last_bytes_bits = 1u8;
681    } else if lgwin == 17i32 {
682        *last_bytes = 1u16;
683        *last_bytes_bits = 7u8;
684    } else if lgwin > 17i32 {
685        *last_bytes = ((lgwin - 17i32) << 1 | 1i32) as u16;
686        *last_bytes_bits = 4u8;
687    } else {
688        *last_bytes = ((lgwin - 8i32) << 4 | 1i32) as u16;
689        *last_bytes_bits = 7u8;
690    }
691}
692
693fn InitCommandPrefixCodes(
694    cmd_depths: &mut [u8],
695    cmd_bits: &mut [u16],
696    cmd_code: &mut [u8],
697    cmd_code_numbits: &mut usize,
698) {
699    static kDefaultCommandDepths: [u8; 128] = [
700        0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6,
701        7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6, 7, 8, 8, 9, 10, 10, 10, 10, 10,
702        10, 10, 10, 10, 10, 10, 10, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 6,
703        6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10, 12, 12,
704        12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0,
705    ];
706    static kDefaultCommandBits: [u16; 128] = [
707        0, 0, 8, 9, 3, 35, 7, 71, 39, 103, 23, 47, 175, 111, 239, 31, 0, 0, 0, 4, 12, 2, 10, 6, 13,
708        29, 11, 43, 27, 59, 87, 55, 15, 79, 319, 831, 191, 703, 447, 959, 0, 14, 1, 25, 5, 21, 19,
709        51, 119, 159, 95, 223, 479, 991, 63, 575, 127, 639, 383, 895, 255, 767, 511, 1023, 14, 0,
710        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8,
711        4, 12, 2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255, 767, 2815, 1791,
712        3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095, 0, 0, 0, 0,
713    ];
714    static kDefaultCommandCode: [u8; 57] = [
715        0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6, 0x70, 0x57, 0xbc,
716        0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c, 0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83,
717        0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa, 0x6, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce,
718        0x88, 0x54, 0x94, 0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x4, 0x0,
719    ];
720    static kDefaultCommandCodeNumBits: usize = 448usize;
721    cmd_depths[..].clone_from_slice(&kDefaultCommandDepths[..]);
722    cmd_bits[..].clone_from_slice(&kDefaultCommandBits[..]);
723    cmd_code[..kDefaultCommandCode.len()].clone_from_slice(&kDefaultCommandCode[..]);
724    *cmd_code_numbits = kDefaultCommandCodeNumBits;
725}
726
727fn EnsureInitialized<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) -> i32 {
728    if s.is_initialized_ {
729        return 1i32;
730    }
731    SanitizeParams(&mut s.params);
732    s.params.lgblock = ComputeLgBlock(&mut s.params);
733    ChooseDistanceParams(&mut s.params);
734    s.remaining_metadata_bytes_ = !(0u32);
735    RingBufferSetup(&mut s.params, &mut s.ringbuffer_);
736    {
737        let mut lgwin: i32 = s.params.lgwin;
738        if s.params.quality == 0i32 || s.params.quality == 1i32 {
739            lgwin = brotli_max_int(lgwin, 18i32);
740        }
741        EncodeWindowBits(
742            lgwin,
743            s.params.large_window,
744            &mut s.last_bytes_,
745            &mut s.last_bytes_bits_,
746        );
747    }
748    if s.params.quality == 0i32 {
749        InitCommandPrefixCodes(
750            &mut s.cmd_depths_[..],
751            &mut s.cmd_bits_[..],
752            &mut s.cmd_code_[..],
753            &mut s.cmd_code_numbits_,
754        );
755    }
756    if s.params.catable {
757        // if we want to properly concatenate, then we need to ignore any distances
758        // this value 0x7ffffff0 was chosen to be larger than max_distance + gap
759        // but small enough so that +/-3 will not overflow (due to distance modifications)
760        for item in s.dist_cache_.iter_mut() {
761            *item = 0x7ffffff0;
762        }
763        for item in s.saved_dist_cache_.iter_mut() {
764            *item = 0x7ffffff0;
765        }
766    }
767    s.is_initialized_ = true;
768    1i32
769}
770
771fn RingBufferInitBuffer<AllocU8: alloc::Allocator<u8>>(
772    m: &mut AllocU8,
773    buflen: u32,
774    rb: &mut RingBuffer<AllocU8>,
775) {
776    static kSlackForEightByteHashingEverywhere: usize = 7usize;
777    let mut new_data = m.alloc_cell(
778        ((2u32).wrapping_add(buflen) as usize).wrapping_add(kSlackForEightByteHashingEverywhere),
779    );
780    let mut i: usize;
781    if !rb.data_mo.slice().is_empty() {
782        let lim: usize = ((2u32).wrapping_add(rb.cur_size_) as usize)
783            .wrapping_add(kSlackForEightByteHashingEverywhere);
784        new_data.slice_mut()[..lim].clone_from_slice(&rb.data_mo.slice()[..lim]);
785        m.free_cell(core::mem::take(&mut rb.data_mo));
786    }
787    let _ = core::mem::replace(&mut rb.data_mo, new_data);
788    rb.cur_size_ = buflen;
789    rb.buffer_index = 2usize;
790    rb.data_mo.slice_mut()[(rb.buffer_index.wrapping_sub(2))] = 0;
791    rb.data_mo.slice_mut()[(rb.buffer_index.wrapping_sub(1))] = 0;
792    i = 0usize;
793    while i < kSlackForEightByteHashingEverywhere {
794        {
795            rb.data_mo.slice_mut()[rb
796                .buffer_index
797                .wrapping_add(rb.cur_size_ as usize)
798                .wrapping_add(i)] = 0;
799        }
800        i = i.wrapping_add(1);
801    }
802}
803
804fn RingBufferWriteTail<AllocU8: alloc::Allocator<u8>>(
805    bytes: &[u8],
806    n: usize,
807    rb: &mut RingBuffer<AllocU8>,
808) {
809    let masked_pos: usize = (rb.pos_ & rb.mask_) as usize;
810    if masked_pos < rb.tail_size_ as usize {
811        let p: usize = (rb.size_ as usize).wrapping_add(masked_pos);
812        let begin = rb.buffer_index.wrapping_add(p);
813        let lim = brotli_min_size_t(n, (rb.tail_size_ as usize).wrapping_sub(masked_pos));
814        rb.data_mo.slice_mut()[begin..(begin + lim)].clone_from_slice(&bytes[..lim]);
815    }
816}
817
818fn RingBufferWrite<AllocU8: alloc::Allocator<u8>>(
819    m: &mut AllocU8,
820    bytes: &[u8],
821    n: usize,
822    rb: &mut RingBuffer<AllocU8>,
823) {
824    if rb.pos_ == 0u32 && (n < rb.tail_size_ as usize) {
825        rb.pos_ = n as u32;
826        RingBufferInitBuffer(m, rb.pos_, rb);
827        rb.data_mo.slice_mut()[rb.buffer_index..(rb.buffer_index + n)]
828            .clone_from_slice(&bytes[..n]);
829        return;
830    }
831    if rb.cur_size_ < rb.total_size_ {
832        RingBufferInitBuffer(m, rb.total_size_, rb);
833        if !(0i32 == 0) {
834            return;
835        }
836        rb.data_mo.slice_mut()[rb
837            .buffer_index
838            .wrapping_add(rb.size_ as usize)
839            .wrapping_sub(2)] = 0u8;
840        rb.data_mo.slice_mut()[rb
841            .buffer_index
842            .wrapping_add(rb.size_ as usize)
843            .wrapping_sub(1)] = 0u8;
844    }
845    {
846        let masked_pos: usize = (rb.pos_ & rb.mask_) as usize;
847        RingBufferWriteTail(bytes, n, rb);
848        if masked_pos.wrapping_add(n) <= rb.size_ as usize {
849            // a single write fits
850            let start = rb.buffer_index.wrapping_add(masked_pos);
851            rb.data_mo.slice_mut()[start..(start + n)].clone_from_slice(&bytes[..n]);
852        } else {
853            {
854                let start = rb.buffer_index.wrapping_add(masked_pos);
855                let mid = brotli_min_size_t(n, (rb.total_size_ as usize).wrapping_sub(masked_pos));
856                rb.data_mo.slice_mut()[start..(start + mid)].clone_from_slice(&bytes[..mid]);
857            }
858            let xstart = rb.buffer_index.wrapping_add(0);
859            let size = n.wrapping_sub((rb.size_ as usize).wrapping_sub(masked_pos));
860            let bytes_start = (rb.size_ as usize).wrapping_sub(masked_pos);
861            rb.data_mo.slice_mut()[xstart..(xstart + size)]
862                .clone_from_slice(&bytes[bytes_start..(bytes_start + size)]);
863        }
864    }
865    let data_2 = rb.data_mo.slice()[rb
866        .buffer_index
867        .wrapping_add(rb.size_ as usize)
868        .wrapping_sub(2)];
869    rb.data_mo.slice_mut()[rb.buffer_index.wrapping_sub(2)] = data_2;
870    let data_1 = rb.data_mo.slice()[rb
871        .buffer_index
872        .wrapping_add(rb.size_ as usize)
873        .wrapping_sub(1)];
874    rb.data_mo.slice_mut()[rb.buffer_index.wrapping_sub(1)] = data_1;
875    rb.pos_ = rb.pos_.wrapping_add(n as u32);
876    if rb.pos_ > 1u32 << 30 {
877        rb.pos_ = rb.pos_ & (1u32 << 30).wrapping_sub(1) | 1u32 << 30;
878    }
879}
880
881fn CopyInputToRingBuffer<Alloc: BrotliAlloc>(
882    s: &mut BrotliEncoderStateStruct<Alloc>,
883    input_size: usize,
884    input_buffer: &[u8],
885) {
886    if EnsureInitialized(s) == 0 {
887        return;
888    }
889    RingBufferWrite(&mut s.m8, input_buffer, input_size, &mut s.ringbuffer_);
890    if !(0i32 == 0) {
891        return;
892    }
893    s.input_pos_ = s.input_pos_.wrapping_add(input_size as u64);
894    if (s.ringbuffer_).pos_ <= (s.ringbuffer_).mask_ {
895        let start = (s.ringbuffer_)
896            .buffer_index
897            .wrapping_add((s.ringbuffer_).pos_ as usize);
898        for item in (s.ringbuffer_).data_mo.slice_mut()[start..(start + 7)].iter_mut() {
899            *item = 0;
900        }
901    }
902}
903
904fn ChooseHasher(params: &mut BrotliEncoderParams) {
905    let hparams = &mut params.hasher;
906    if params.quality >= 10 && !params.q9_5 {
907        hparams.type_ = 10;
908    } else if params.quality == 10 {
909        // we are using quality 10 as a proxy for "9.5"
910        hparams.type_ = 9;
911        hparams.num_last_distances_to_check = H9_NUM_LAST_DISTANCES_TO_CHECK as i32;
912        hparams.block_bits = H9_BLOCK_BITS as i32;
913        hparams.bucket_bits = H9_BUCKET_BITS as i32;
914        hparams.hash_len = 4;
915    } else if params.quality == 9 {
916        hparams.type_ = 9;
917        hparams.num_last_distances_to_check = H9_NUM_LAST_DISTANCES_TO_CHECK as i32;
918        hparams.block_bits = H9_BLOCK_BITS as i32;
919        hparams.bucket_bits = H9_BUCKET_BITS as i32;
920        hparams.hash_len = 4;
921    } else if params.quality == 4 && (params.size_hint >= (1i32 << 20) as usize) {
922        hparams.type_ = 54i32;
923    } else if params.quality < 5 {
924        hparams.type_ = params.quality;
925    } else if params.lgwin <= 16 {
926        hparams.type_ = if params.quality < 7 {
927            40i32
928        } else if params.quality < 9 {
929            41i32
930        } else {
931            42i32
932        };
933    } else if ((params.q9_5 && params.size_hint > (1 << 20)) || params.size_hint > (1 << 22))
934        && (params.lgwin >= 19i32)
935    {
936        hparams.type_ = 6i32;
937        hparams.block_bits = core::cmp::min(params.quality - 1, 9);
938        hparams.bucket_bits = 15i32;
939        hparams.hash_len = 5i32;
940        hparams.num_last_distances_to_check = if params.quality < 7 {
941            4i32
942        } else if params.quality < 9 {
943            10i32
944        } else {
945            16i32
946        };
947    } else {
948        hparams.type_ = 5i32;
949        hparams.block_bits = core::cmp::min(params.quality - 1, 9);
950        hparams.bucket_bits = if params.quality < 7 && params.size_hint <= (1 << 20) {
951            14i32
952        } else {
953            15i32
954        };
955        hparams.num_last_distances_to_check = if params.quality < 7 {
956            4i32
957        } else if params.quality < 9 {
958            10i32
959        } else {
960            16i32
961        };
962    }
963}
964
965fn InitializeH2<AllocU32: alloc::Allocator<u32>>(
966    m32: &mut AllocU32,
967    params: &BrotliEncoderParams,
968) -> BasicHasher<H2Sub<AllocU32>> {
969    BasicHasher {
970        GetHasherCommon: Struct1 {
971            params: params.hasher,
972            is_prepared_: 1,
973            dict_num_lookups: 0,
974            dict_num_matches: 0,
975        },
976        buckets_: H2Sub {
977            buckets_: m32.alloc_cell(65537 + 8),
978        },
979        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
980    }
981}
982fn InitializeH3<AllocU32: alloc::Allocator<u32>>(
983    m32: &mut AllocU32,
984    params: &BrotliEncoderParams,
985) -> BasicHasher<H3Sub<AllocU32>> {
986    BasicHasher {
987        GetHasherCommon: Struct1 {
988            params: params.hasher,
989            is_prepared_: 1,
990            dict_num_lookups: 0,
991            dict_num_matches: 0,
992        },
993        buckets_: H3Sub {
994            buckets_: m32.alloc_cell(65538 + 8),
995        },
996        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
997    }
998}
999fn InitializeH4<AllocU32: alloc::Allocator<u32>>(
1000    m32: &mut AllocU32,
1001    params: &BrotliEncoderParams,
1002) -> BasicHasher<H4Sub<AllocU32>> {
1003    BasicHasher {
1004        GetHasherCommon: Struct1 {
1005            params: params.hasher,
1006            is_prepared_: 1,
1007            dict_num_lookups: 0,
1008            dict_num_matches: 0,
1009        },
1010        buckets_: H4Sub {
1011            buckets_: m32.alloc_cell(131072 + 8),
1012        },
1013        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1014    }
1015}
1016fn InitializeH54<AllocU32: alloc::Allocator<u32>>(
1017    m32: &mut AllocU32,
1018    params: &BrotliEncoderParams,
1019) -> BasicHasher<H54Sub<AllocU32>> {
1020    BasicHasher {
1021        GetHasherCommon: Struct1 {
1022            params: params.hasher,
1023            is_prepared_: 1,
1024            dict_num_lookups: 0,
1025            dict_num_matches: 0,
1026        },
1027        buckets_: H54Sub {
1028            buckets_: m32.alloc_cell(1048580 + 8),
1029        },
1030        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1031    }
1032}
1033
1034fn InitializeH9<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1035    m16: &mut Alloc,
1036    params: &BrotliEncoderParams,
1037) -> H9<Alloc> {
1038    H9 {
1039        dict_search_stats_: Struct1 {
1040            params: params.hasher,
1041            is_prepared_: 1,
1042            dict_num_lookups: 0,
1043            dict_num_matches: 0,
1044        },
1045        num_: <Alloc as Allocator<u16>>::alloc_cell(m16, 1 << H9_BUCKET_BITS),
1046        buckets_: <Alloc as Allocator<u32>>::alloc_cell(m16, H9_BLOCK_SIZE << H9_BUCKET_BITS),
1047        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1048    }
1049}
1050
1051fn InitializeH5<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1052    m16: &mut Alloc,
1053    params: &BrotliEncoderParams,
1054) -> UnionHasher<Alloc> {
1055    let block_size = 1u64 << params.hasher.block_bits;
1056    let bucket_size = 1u64 << params.hasher.bucket_bits;
1057    let buckets: <Alloc as Allocator<u32>>::AllocatedMemory =
1058        <Alloc as Allocator<u32>>::alloc_cell(m16, (bucket_size * block_size) as usize);
1059    let num: <Alloc as Allocator<u16>>::AllocatedMemory =
1060        <Alloc as Allocator<u16>>::alloc_cell(m16, bucket_size as usize);
1061
1062    if params.hasher.block_bits == (HQ5Sub {}).block_bits()
1063        && (1 << params.hasher.bucket_bits) == (HQ5Sub {}).bucket_size()
1064    {
1065        return UnionHasher::H5q5(AdvHasher {
1066            buckets,
1067            h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1068            num,
1069            GetHasherCommon: Struct1 {
1070                params: params.hasher,
1071                is_prepared_: 1,
1072                dict_num_lookups: 0,
1073                dict_num_matches: 0,
1074            },
1075            specialization: HQ5Sub {},
1076        });
1077    }
1078    if params.hasher.block_bits == (HQ7Sub {}).block_bits()
1079        && (1 << params.hasher.bucket_bits) == (HQ7Sub {}).bucket_size()
1080    {
1081        return UnionHasher::H5q7(AdvHasher {
1082            buckets,
1083            h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1084            num,
1085            GetHasherCommon: Struct1 {
1086                params: params.hasher,
1087                is_prepared_: 1,
1088                dict_num_lookups: 0,
1089                dict_num_matches: 0,
1090            },
1091            specialization: HQ7Sub {},
1092        });
1093    }
1094    UnionHasher::H5(AdvHasher {
1095        buckets,
1096        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1097        num,
1098        GetHasherCommon: Struct1 {
1099            params: params.hasher,
1100            is_prepared_: 1,
1101            dict_num_lookups: 0,
1102            dict_num_matches: 0,
1103        },
1104        specialization: H5Sub {
1105            hash_shift_: 32i32 - params.hasher.bucket_bits,
1106            bucket_size_: bucket_size as u32,
1107            block_bits_: params.hasher.block_bits,
1108            block_mask_: block_size.wrapping_sub(1) as u32,
1109        },
1110    })
1111}
1112fn InitializeH6<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1113    m16: &mut Alloc,
1114    params: &BrotliEncoderParams,
1115) -> UnionHasher<Alloc> {
1116    let block_size = 1u64 << params.hasher.block_bits;
1117    let bucket_size = 1u64 << params.hasher.bucket_bits;
1118    let buckets: <Alloc as Allocator<u32>>::AllocatedMemory =
1119        <Alloc as Allocator<u32>>::alloc_cell(m16, (bucket_size * block_size) as usize);
1120    let num: <Alloc as Allocator<u16>>::AllocatedMemory =
1121        <Alloc as Allocator<u16>>::alloc_cell(m16, bucket_size as usize);
1122    UnionHasher::H6(AdvHasher {
1123        buckets,
1124        num,
1125        h9_opts: super::backward_references::H9Opts::new(&params.hasher),
1126        GetHasherCommon: Struct1 {
1127            params: params.hasher,
1128            is_prepared_: 1,
1129            dict_num_lookups: 0,
1130            dict_num_matches: 0,
1131        },
1132        specialization: H6Sub {
1133            bucket_size_: 1u32 << params.hasher.bucket_bits,
1134            block_bits_: params.hasher.block_bits,
1135            block_mask_: block_size.wrapping_sub(1) as u32,
1136            hash_mask: 0xffffffffffffffffu64 >> (64i32 - 8i32 * params.hasher.hash_len),
1137            hash_shift_: 64i32 - params.hasher.bucket_bits,
1138        },
1139    })
1140}
1141
1142fn BrotliMakeHasher<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1143    m: &mut Alloc,
1144    params: &BrotliEncoderParams,
1145) -> UnionHasher<Alloc> {
1146    let hasher_type: i32 = params.hasher.type_;
1147    if hasher_type == 2i32 {
1148        return UnionHasher::H2(InitializeH2(m, params));
1149    }
1150    if hasher_type == 3i32 {
1151        return UnionHasher::H3(InitializeH3(m, params));
1152    }
1153    if hasher_type == 4i32 {
1154        return UnionHasher::H4(InitializeH4(m, params));
1155    }
1156    if hasher_type == 5i32 {
1157        return InitializeH5(m, params);
1158    }
1159    if hasher_type == 6i32 {
1160        return InitializeH6(m, params);
1161    }
1162    if hasher_type == 9i32 {
1163        return UnionHasher::H9(InitializeH9(m, params));
1164    }
1165    /*
1166        if hasher_type == 40i32 {
1167          return InitializeH40(params);
1168        }
1169        if hasher_type == 41i32 {
1170          return InitializeH41(params);
1171        }
1172        if hasher_type == 42i32 {
1173          return InitializeH42(params);
1174        }
1175    */
1176    if hasher_type == 54i32 {
1177        return UnionHasher::H54(InitializeH54(m, params));
1178    }
1179    if hasher_type == 10i32 {
1180        return UnionHasher::H10(InitializeH10(m, false, params, 0));
1181    }
1182    // since we don't support all of these, fall back to something sane
1183    InitializeH6(m, params)
1184
1185    //  return UnionHasher::Uninit;
1186}
1187fn HasherReset<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(t: &mut UnionHasher<Alloc>) {
1188    match t {
1189        &mut UnionHasher::Uninit => {}
1190        _ => (t.GetHasherCommon()).is_prepared_ = 0i32,
1191    };
1192}
1193fn GetHasherCommon<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1194    t: &mut UnionHasher<Alloc>,
1195) -> &mut Struct1 {
1196    t.GetHasherCommon()
1197}
1198
1199pub fn HasherSetup<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1200    m16: &mut Alloc,
1201    handle: &mut UnionHasher<Alloc>,
1202    params: &mut BrotliEncoderParams,
1203    data: &[u8],
1204    position: usize,
1205    input_size: usize,
1206    is_last: i32,
1207) {
1208    let one_shot: i32 = (position == 0usize && (is_last != 0)) as i32;
1209    let is_uninit = match (handle) {
1210        &mut UnionHasher::Uninit => true,
1211        _ => false,
1212    };
1213    if is_uninit {
1214        //let alloc_size: usize;
1215        ChooseHasher(&mut (*params));
1216        //alloc_size = HasherSize(params, one_shot, input_size);
1217        //xself = BrotliAllocate(m, alloc_size.wrapping_mul(::core::mem::size_of::<u8>()))
1218        *handle = BrotliMakeHasher(m16, params);
1219        handle.GetHasherCommon().params = params.hasher;
1220        HasherReset(handle); // this sets everything to zero, unlike in C
1221        handle.GetHasherCommon().is_prepared_ = 1;
1222    } else {
1223        match handle.Prepare(one_shot != 0, input_size, data) {
1224            HowPrepared::ALREADY_PREPARED => {}
1225            HowPrepared::NEWLY_PREPARED => {
1226                if position == 0usize {
1227                    let common = handle.GetHasherCommon();
1228                    common.dict_num_lookups = 0usize;
1229                    common.dict_num_matches = 0usize;
1230                }
1231            }
1232        }
1233    }
1234}
1235
1236fn HasherPrependCustomDictionary<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1237    m: &mut Alloc,
1238    handle: &mut UnionHasher<Alloc>,
1239    params: &mut BrotliEncoderParams,
1240    size: usize,
1241    dict: &[u8],
1242) {
1243    HasherSetup(m, handle, params, dict, 0usize, size, 0i32);
1244    match handle {
1245        &mut UnionHasher::H2(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1246        &mut UnionHasher::H3(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1247        &mut UnionHasher::H4(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1248        &mut UnionHasher::H5(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1249        &mut UnionHasher::H5q7(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1250        &mut UnionHasher::H5q5(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1251        &mut UnionHasher::H6(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1252        &mut UnionHasher::H9(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1253        &mut UnionHasher::H54(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1254        &mut UnionHasher::H10(ref mut hasher) => StoreLookaheadThenStore(hasher, size, dict),
1255        &mut UnionHasher::Uninit => panic!("Uninitialized"),
1256    }
1257}
1258
1259pub fn BrotliEncoderSetCustomDictionary<Alloc: BrotliAlloc>(
1260    s: &mut BrotliEncoderStateStruct<Alloc>,
1261    size: usize,
1262    dict: &[u8],
1263) {
1264    BrotliEncoderSetCustomDictionaryWithOptionalPrecomputedHasher(
1265        s,
1266        size,
1267        dict,
1268        UnionHasher::Uninit,
1269    )
1270}
1271
1272pub fn BrotliEncoderSetCustomDictionaryWithOptionalPrecomputedHasher<Alloc: BrotliAlloc>(
1273    s: &mut BrotliEncoderStateStruct<Alloc>,
1274    size: usize,
1275    mut dict: &[u8],
1276    opt_hasher: UnionHasher<Alloc>,
1277) {
1278    let has_optional_hasher = if let UnionHasher::Uninit = opt_hasher {
1279        false
1280    } else {
1281        true
1282    };
1283    let max_dict_size: usize = (1usize << s.params.lgwin).wrapping_sub(16);
1284    s.hasher_ = opt_hasher;
1285    let mut dict_size: usize = size;
1286    if EnsureInitialized(s) == 0 {
1287        return;
1288    }
1289    if dict_size == 0usize || s.params.quality == 0i32 || s.params.quality == 1i32 || size <= 1 {
1290        s.params.catable = true; // don't risk a too-short dictionary
1291        s.params.appendable = true; // don't risk a too-short dictionary
1292        return;
1293    }
1294    s.custom_dictionary = true;
1295    if size > max_dict_size {
1296        dict = &dict[size.wrapping_sub(max_dict_size)..];
1297        dict_size = max_dict_size;
1298    }
1299    CopyInputToRingBuffer(s, dict_size, dict);
1300    s.last_flush_pos_ = dict_size as u64;
1301    s.last_processed_pos_ = dict_size as u64;
1302    if dict_size > 0 {
1303        s.prev_byte_ = dict[dict_size.wrapping_sub(1)];
1304    }
1305    if dict_size > 1 {
1306        s.prev_byte2_ = dict[dict_size.wrapping_sub(2)];
1307    }
1308    let m16 = &mut s.m8;
1309    if cfg!(debug_assertions) || !has_optional_hasher {
1310        let mut orig_hasher = UnionHasher::Uninit;
1311        if has_optional_hasher {
1312            orig_hasher = core::mem::replace(&mut s.hasher_, UnionHasher::Uninit);
1313        }
1314        HasherPrependCustomDictionary(m16, &mut s.hasher_, &mut s.params, dict_size, dict);
1315        if has_optional_hasher {
1316            debug_assert!(orig_hasher == s.hasher_);
1317            DestroyHasher(m16, &mut orig_hasher);
1318        }
1319    }
1320}
1321pub fn BrotliEncoderMaxCompressedSizeMulti(input_size: usize, num_threads: usize) -> usize {
1322    BrotliEncoderMaxCompressedSize(input_size) + num_threads * 8
1323}
1324
1325pub fn BrotliEncoderMaxCompressedSize(input_size: usize) -> usize {
1326    let magic_size = 16usize;
1327    let num_large_blocks: usize = input_size >> 14;
1328    let tail: usize = input_size.wrapping_sub(num_large_blocks << 24);
1329    let tail_overhead: usize = (if tail > (1i32 << 20) as usize {
1330        4i32
1331    } else {
1332        3i32
1333    }) as usize;
1334    let overhead: usize = (2usize)
1335        .wrapping_add((4usize).wrapping_mul(num_large_blocks))
1336        .wrapping_add(tail_overhead)
1337        .wrapping_add(1);
1338    let result: usize = input_size.wrapping_add(overhead);
1339    if input_size == 0usize {
1340        return 1 + magic_size;
1341    }
1342    if result < input_size {
1343        0usize
1344    } else {
1345        result + magic_size
1346    }
1347}
1348
1349fn InitOrStitchToPreviousBlock<Alloc: alloc::Allocator<u16> + alloc::Allocator<u32>>(
1350    m: &mut Alloc,
1351    handle: &mut UnionHasher<Alloc>,
1352    data: &[u8],
1353    mask: usize,
1354    params: &mut BrotliEncoderParams,
1355    position: usize,
1356    input_size: usize,
1357    is_last: bool,
1358) {
1359    HasherSetup(
1360        m,
1361        handle,
1362        params,
1363        data,
1364        position,
1365        input_size,
1366        is_last as i32,
1367    );
1368    handle.StitchToPreviousBlock(input_size, position, data, mask);
1369}
1370
1371pub fn InitInsertCommand(xself: &mut Command, insertlen: usize) {
1372    xself.insert_len_ = insertlen as u32;
1373    xself.copy_len_ = (4i32 << 25) as u32;
1374    xself.dist_extra_ = 0u32;
1375    xself.dist_prefix_ = (1u16 << 10) | BROTLI_NUM_DISTANCE_SHORT_CODES as u16;
1376    GetLengthCode(insertlen, 4usize, 0i32, &mut xself.cmd_prefix_);
1377}
1378
1379fn ShouldCompress(
1380    data: &[u8],
1381    mask: usize,
1382    last_flush_pos: u64,
1383    bytes: usize,
1384    num_literals: usize,
1385    num_commands: usize,
1386) -> i32 {
1387    if num_commands < (bytes >> 8).wrapping_add(2)
1388        && num_literals as (super::util::floatX)
1389            > 0.99 as super::util::floatX * bytes as (super::util::floatX)
1390    {
1391        let mut literal_histo = [0u32; 256];
1392        static kSampleRate: u32 = 13u32;
1393        static kMinEntropy: super::util::floatX = 7.92 as super::util::floatX;
1394        let bit_cost_threshold: super::util::floatX =
1395            bytes as (super::util::floatX) * kMinEntropy / kSampleRate as (super::util::floatX);
1396        let t: usize = bytes
1397            .wrapping_add(kSampleRate as usize)
1398            .wrapping_sub(1)
1399            .wrapping_div(kSampleRate as usize);
1400        let mut pos: u32 = last_flush_pos as u32;
1401        let mut i: usize;
1402        i = 0usize;
1403        while i < t {
1404            {
1405                {
1406                    let _rhs = 1;
1407                    let _lhs = &mut literal_histo[data[(pos as usize & mask)] as usize];
1408                    *_lhs = (*_lhs).wrapping_add(_rhs as u32);
1409                }
1410                pos = pos.wrapping_add(kSampleRate);
1411            }
1412            i = i.wrapping_add(1);
1413        }
1414        if BitsEntropy(&literal_histo[..], 256usize) > bit_cost_threshold {
1415            return 0i32;
1416        }
1417    }
1418    1i32
1419}
1420
1421/* Chooses the literal context mode for a metablock */
1422fn ChooseContextMode(
1423    params: &BrotliEncoderParams,
1424    data: &[u8],
1425    pos: usize,
1426    mask: usize,
1427    length: usize,
1428) -> ContextType {
1429    /* We only do the computation for the option of something else than
1430    CONTEXT_UTF8 for the highest qualities */
1431    match params.mode {
1432        BrotliEncoderMode::BROTLI_FORCE_LSB_PRIOR => return ContextType::CONTEXT_LSB6,
1433        BrotliEncoderMode::BROTLI_FORCE_MSB_PRIOR => return ContextType::CONTEXT_MSB6,
1434        BrotliEncoderMode::BROTLI_FORCE_UTF8_PRIOR => return ContextType::CONTEXT_UTF8,
1435        BrotliEncoderMode::BROTLI_FORCE_SIGNED_PRIOR => return ContextType::CONTEXT_SIGNED,
1436        _ => {}
1437    }
1438    if (params.quality >= 10 && BrotliIsMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio) == 0) {
1439        return ContextType::CONTEXT_SIGNED;
1440    }
1441    ContextType::CONTEXT_UTF8
1442}
1443
1444#[derive(PartialEq, Eq, Copy, Clone)]
1445pub enum BrotliEncoderOperation {
1446    BROTLI_OPERATION_PROCESS = 0,
1447    BROTLI_OPERATION_FLUSH = 1,
1448    BROTLI_OPERATION_FINISH = 2,
1449    BROTLI_OPERATION_EMIT_METADATA = 3,
1450}
1451
1452fn MakeUncompressedStream(input: &[u8], input_size: usize, output: &mut [u8]) -> usize {
1453    let mut size: usize = input_size;
1454    let mut result: usize = 0usize;
1455    let mut offset: usize = 0usize;
1456    if input_size == 0usize {
1457        output[0] = 6u8;
1458        return 1;
1459    }
1460    output[result] = 0x21u8;
1461    result = result.wrapping_add(1);
1462    output[result] = 0x3u8;
1463    result = result.wrapping_add(1);
1464    while size > 0usize {
1465        let mut nibbles: u32 = 0u32;
1466
1467        let chunk_size: u32 = if size > (1u32 << 24) as usize {
1468            1u32 << 24
1469        } else {
1470            size as u32
1471        };
1472        if chunk_size > 1u32 << 16 {
1473            nibbles = if chunk_size > 1u32 << 20 { 2i32 } else { 1i32 } as u32;
1474        }
1475        let bits: u32 = nibbles << 1
1476            | chunk_size.wrapping_sub(1) << 3
1477            | 1u32 << (19u32).wrapping_add((4u32).wrapping_mul(nibbles));
1478        output[result] = bits as u8;
1479        result = result.wrapping_add(1);
1480        output[result] = (bits >> 8) as u8;
1481        result = result.wrapping_add(1);
1482        output[result] = (bits >> 16) as u8;
1483        result = result.wrapping_add(1);
1484        if nibbles == 2u32 {
1485            output[result] = (bits >> 24) as u8;
1486            result = result.wrapping_add(1);
1487        }
1488        output[result..(result + chunk_size as usize)]
1489            .clone_from_slice(&input[offset..(offset + chunk_size as usize)]);
1490        result = result.wrapping_add(chunk_size as usize);
1491        offset = offset.wrapping_add(chunk_size as usize);
1492        size = size.wrapping_sub(chunk_size as usize);
1493    }
1494    output[result] = 3u8;
1495    result = result.wrapping_add(1);
1496    result
1497}
1498pub fn BrotliEncoderCompress<
1499    Alloc: BrotliAlloc,
1500    MetablockCallback: FnMut(
1501        &mut interface::PredictionModeContextMap<InputReferenceMut>,
1502        &mut [interface::StaticCommand],
1503        interface::InputPair,
1504        &mut Alloc,
1505    ),
1506>(
1507    empty_m8: Alloc,
1508    m8: &mut Alloc,
1509    quality: i32,
1510    lgwin: i32,
1511    mode: BrotliEncoderMode,
1512    input_size: usize,
1513    input_buffer: &[u8],
1514    encoded_size: &mut usize,
1515    encoded_buffer: &mut [u8],
1516    metablock_callback: &mut MetablockCallback,
1517) -> i32 {
1518    let out_size: usize = *encoded_size;
1519    let input_start = input_buffer;
1520    let output_start = encoded_buffer;
1521    let max_out_size: usize = BrotliEncoderMaxCompressedSize(input_size);
1522    if out_size == 0usize {
1523        return 0i32;
1524    }
1525    if input_size == 0usize {
1526        *encoded_size = 1;
1527        output_start[0] = 6;
1528        return 1i32;
1529    }
1530    let mut is_fallback: i32 = 0i32;
1531    if quality == 10i32 {
1532        panic!("Unimplemented: need to set 9.5 here");
1533    }
1534    if is_fallback == 0 {
1535        let mut s_orig = BrotliEncoderCreateInstance(core::mem::replace(m8, empty_m8));
1536        let mut result: i32;
1537        {
1538            let s = &mut s_orig;
1539            let mut available_in: usize = input_size;
1540            let next_in_array: &[u8] = input_buffer;
1541            let mut next_in_offset: usize = 0;
1542            let mut available_out: usize = *encoded_size;
1543            let next_out_array: &mut [u8] = output_start;
1544            let mut next_out_offset: usize = 0;
1545            let mut total_out = Some(0);
1546            BrotliEncoderSetParameter(
1547                s,
1548                BrotliEncoderParameter::BROTLI_PARAM_QUALITY,
1549                quality as u32,
1550            );
1551            BrotliEncoderSetParameter(s, BrotliEncoderParameter::BROTLI_PARAM_LGWIN, lgwin as u32);
1552            BrotliEncoderSetParameter(s, BrotliEncoderParameter::BROTLI_PARAM_MODE, mode as u32);
1553            BrotliEncoderSetParameter(
1554                s,
1555                BrotliEncoderParameter::BROTLI_PARAM_SIZE_HINT,
1556                input_size as u32,
1557            );
1558            if lgwin > BROTLI_MAX_WINDOW_BITS as i32 {
1559                BrotliEncoderSetParameter(s, BrotliEncoderParameter::BROTLI_PARAM_LARGE_WINDOW, 1);
1560            }
1561            result = BrotliEncoderCompressStream(
1562                s,
1563                BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
1564                &mut available_in,
1565                next_in_array,
1566                &mut next_in_offset,
1567                &mut available_out,
1568                next_out_array,
1569                &mut next_out_offset,
1570                &mut total_out,
1571                metablock_callback,
1572            );
1573            if BrotliEncoderIsFinished(s) == 0 {
1574                result = 0i32;
1575            }
1576
1577            *encoded_size = total_out.unwrap();
1578            BrotliEncoderDestroyInstance(s);
1579        }
1580        let _ = core::mem::replace(m8, s_orig.m8);
1581        if result == 0 || max_out_size != 0 && (*encoded_size > max_out_size) {
1582            is_fallback = 1i32;
1583        } else {
1584            return 1i32;
1585        }
1586    }
1587    assert_ne!(is_fallback, 0);
1588    *encoded_size = 0usize;
1589    if max_out_size == 0 {
1590        return 0i32;
1591    }
1592    if out_size >= max_out_size {
1593        *encoded_size = MakeUncompressedStream(input_start, input_size, output_start);
1594        return 1i32;
1595    }
1596    0i32
1597}
1598
1599fn InjectBytePaddingBlock<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) {
1600    let mut seal: u32 = s.last_bytes_ as u32;
1601    let mut seal_bits: usize = s.last_bytes_bits_ as usize;
1602    let destination: &mut [u8];
1603    s.last_bytes_ = 0;
1604    s.last_bytes_bits_ = 0;
1605    seal |= 0x6u32 << seal_bits;
1606
1607    seal_bits = seal_bits.wrapping_add(6);
1608    if !IsNextOutNull(&s.next_out_) {
1609        destination = &mut GetNextOut!(*s)[s.available_out_..];
1610    } else {
1611        destination = &mut s.tiny_buf_[..];
1612        s.next_out_ = NextOut::TinyBuf(0);
1613    }
1614    destination[0] = seal as u8;
1615    if seal_bits > 8usize {
1616        destination[1] = (seal >> 8) as u8;
1617    }
1618    if seal_bits > 16usize {
1619        destination[2] = (seal >> 16) as u8;
1620    }
1621    s.available_out_ = s
1622        .available_out_
1623        .wrapping_add(seal_bits.wrapping_add(7) >> 3);
1624}
1625fn InjectFlushOrPushOutput<Alloc: BrotliAlloc>(
1626    s: &mut BrotliEncoderStateStruct<Alloc>,
1627    available_out: &mut usize,
1628    next_out_array: &mut [u8],
1629    next_out_offset: &mut usize,
1630    total_out: &mut Option<usize>,
1631) -> i32 {
1632    if s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_FLUSH_REQUESTED as i32
1633        && (s.last_bytes_bits_ as i32 != 0i32)
1634    {
1635        InjectBytePaddingBlock(s);
1636        return 1i32;
1637    }
1638    if s.available_out_ != 0usize && (*available_out != 0usize) {
1639        let copy_output_size: usize = brotli_min_size_t(s.available_out_, *available_out);
1640        (*next_out_array)[(*next_out_offset)..(*next_out_offset + copy_output_size)]
1641            .clone_from_slice(&GetNextOut!(s)[..copy_output_size]);
1642        //memcpy(*next_out, s.next_out_, copy_output_size);
1643        *next_out_offset = next_out_offset.wrapping_add(copy_output_size);
1644        *available_out = available_out.wrapping_sub(copy_output_size);
1645        s.next_out_ = NextOutIncrement(&s.next_out_, (copy_output_size as i32));
1646        s.available_out_ = s.available_out_.wrapping_sub(copy_output_size);
1647        s.total_out_ = s.total_out_.wrapping_add(copy_output_size as u64);
1648        if let &mut Some(ref mut total_out_inner) = total_out {
1649            *total_out_inner = s.total_out_ as usize;
1650        }
1651        return 1i32;
1652    }
1653    0i32
1654}
1655
1656fn UnprocessedInputSize<Alloc: BrotliAlloc>(s: &BrotliEncoderStateStruct<Alloc>) -> u64 {
1657    s.input_pos_.wrapping_sub(s.last_processed_pos_)
1658}
1659
1660fn UpdateSizeHint<Alloc: BrotliAlloc>(
1661    s: &mut BrotliEncoderStateStruct<Alloc>,
1662    available_in: usize,
1663) {
1664    if s.params.size_hint == 0usize {
1665        let delta: u64 = UnprocessedInputSize(s);
1666        let tail: u64 = available_in as u64;
1667        let limit: u32 = 1u32 << 30;
1668        let total: u32;
1669        if delta >= u64::from(limit)
1670            || tail >= u64::from(limit)
1671            || delta.wrapping_add(tail) >= u64::from(limit)
1672        {
1673            total = limit;
1674        } else {
1675            total = delta.wrapping_add(tail) as u32;
1676        }
1677        s.params.size_hint = total as usize;
1678    }
1679}
1680
1681fn WrapPosition(position: u64) -> u32 {
1682    let mut result: u32 = position as u32;
1683    let gb: u64 = position >> 30;
1684    if gb > 2 {
1685        result = result & (1u32 << 30).wrapping_sub(1)
1686            | ((gb.wrapping_sub(1) & 1) as u32).wrapping_add(1) << 30;
1687    }
1688    result
1689}
1690
1691fn InputBlockSize<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) -> usize {
1692    if EnsureInitialized(s) == 0 {
1693        return 0usize;
1694    }
1695    1 << s.params.lgblock
1696}
1697
1698fn GetBrotliStorage<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>, size: usize) {
1699    if s.storage_size_ < size {
1700        <Alloc as Allocator<u8>>::free_cell(&mut s.m8, core::mem::take(&mut s.storage_));
1701        s.storage_ = <Alloc as Allocator<u8>>::alloc_cell(&mut s.m8, size);
1702        s.storage_size_ = size;
1703    }
1704}
1705
1706fn MaxHashTableSize(quality: i32) -> usize {
1707    (if quality == 0i32 {
1708        1i32 << 15
1709    } else {
1710        1i32 << 17
1711    }) as usize
1712}
1713
1714fn HashTableSize(max_table_size: usize, input_size: usize) -> usize {
1715    let mut htsize: usize = 256usize;
1716    while htsize < max_table_size && (htsize < input_size) {
1717        htsize <<= 1i32;
1718    }
1719    htsize
1720}
1721
1722macro_rules! GetHashTable {
1723    ($s : expr, $quality: expr, $input_size : expr, $table_size : expr) => {
1724        GetHashTableInternal(
1725            &mut $s.m8,
1726            &mut $s.small_table_,
1727            &mut $s.large_table_,
1728            $quality,
1729            $input_size,
1730            $table_size,
1731        )
1732    };
1733}
1734fn GetHashTableInternal<'a, AllocI32: alloc::Allocator<i32>>(
1735    mi32: &mut AllocI32,
1736    small_table_: &'a mut [i32; 1024],
1737    large_table_: &'a mut AllocI32::AllocatedMemory,
1738    quality: i32,
1739    input_size: usize,
1740    table_size: &mut usize,
1741) -> &'a mut [i32] {
1742    let max_table_size: usize = MaxHashTableSize(quality);
1743    let mut htsize: usize = HashTableSize(max_table_size, input_size);
1744    let table: &mut [i32];
1745    if quality == 0i32 && htsize & 0xaaaaausize == 0usize {
1746        htsize <<= 1i32;
1747    }
1748    if htsize <= small_table_.len() {
1749        table = &mut small_table_[..];
1750    } else {
1751        if htsize > large_table_.slice().len() {
1752            //s.large_table_size_ = htsize;
1753            {
1754                mi32.free_cell(core::mem::take(large_table_));
1755            }
1756            *large_table_ = mi32.alloc_cell(htsize);
1757        }
1758        table = large_table_.slice_mut();
1759    }
1760    *table_size = htsize;
1761    for item in table[..htsize].iter_mut() {
1762        *item = 0;
1763    }
1764    table // FIXME: probably need a macro to do this without borrowing the whole EncoderStateStruct
1765}
1766fn UpdateLastProcessedPos<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) -> bool {
1767    let wrapped_last_processed_pos: u32 = WrapPosition(s.last_processed_pos_);
1768    let wrapped_input_pos: u32 = WrapPosition(s.input_pos_);
1769    s.last_processed_pos_ = s.input_pos_;
1770    wrapped_input_pos < wrapped_last_processed_pos
1771}
1772
1773fn MaxMetablockSize(params: &BrotliEncoderParams) -> usize {
1774    let bits: i32 = brotli_min_int(ComputeRbBits(params), 24i32);
1775    1 << bits
1776}
1777
1778fn ChooseContextMap(
1779    quality: i32,
1780    bigram_histo: &mut [u32],
1781    num_literal_contexts: &mut usize,
1782    literal_context_map: &mut &[u32],
1783) {
1784    static kStaticContextMapContinuation: [u32; 64] = [
1785        1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1786        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1787        0, 0, 0, 0,
1788    ];
1789    static kStaticContextMapSimpleUTF8: [u32; 64] = [
1790        0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1791        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1792        0, 0, 0, 0,
1793    ];
1794    let mut monogram_histo = [0u32; 3];
1795    let mut two_prefix_histo = [0u32; 6];
1796
1797    let mut i: usize;
1798    let mut dummy: usize = 0;
1799    let mut entropy: [super::util::floatX; 4] = [0.0 as super::util::floatX; 4];
1800    i = 0usize;
1801    while i < 9usize {
1802        {
1803            {
1804                let _rhs = bigram_histo[i];
1805                let _lhs = &mut monogram_histo[i.wrapping_rem(3)];
1806                *_lhs = (*_lhs).wrapping_add(_rhs);
1807            }
1808            {
1809                let _rhs = bigram_histo[i];
1810                let _lhs = &mut two_prefix_histo[i.wrapping_rem(6)];
1811                *_lhs = (*_lhs).wrapping_add(_rhs);
1812            }
1813        }
1814        i = i.wrapping_add(1);
1815    }
1816    entropy[1] = ShannonEntropy(&monogram_histo[..], 3usize, &mut dummy);
1817    entropy[2] = ShannonEntropy(&two_prefix_histo[..], 3usize, &mut dummy)
1818        + ShannonEntropy(&two_prefix_histo[3..], 3usize, &mut dummy);
1819    entropy[3] = 0i32 as (super::util::floatX);
1820    i = 0usize;
1821    while i < 3usize {
1822        {
1823            let _rhs = ShannonEntropy(
1824                &bigram_histo[(3usize).wrapping_mul(i)..],
1825                3usize,
1826                &mut dummy,
1827            );
1828            let _lhs = &mut entropy[3];
1829            *_lhs += _rhs;
1830        }
1831        i = i.wrapping_add(1);
1832    }
1833    let total: usize = monogram_histo[0]
1834        .wrapping_add(monogram_histo[1])
1835        .wrapping_add(monogram_histo[2]) as usize;
1836    0i32;
1837    entropy[0] = 1.0 as super::util::floatX / total as (super::util::floatX);
1838    {
1839        let _rhs = entropy[0];
1840        let _lhs = &mut entropy[1];
1841        *_lhs *= _rhs;
1842    }
1843    {
1844        let _rhs = entropy[0];
1845        let _lhs = &mut entropy[2];
1846        *_lhs *= _rhs;
1847    }
1848    {
1849        let _rhs = entropy[0];
1850        let _lhs = &mut entropy[3];
1851        *_lhs *= _rhs;
1852    }
1853    if quality < 7i32 {
1854        entropy[3] = entropy[1] * 10i32 as (super::util::floatX);
1855    }
1856    if entropy[1] - entropy[2] < 0.2 as super::util::floatX
1857        && (entropy[1] - entropy[3] < 0.2 as super::util::floatX)
1858    {
1859        *num_literal_contexts = 1;
1860    } else if entropy[2] - entropy[3] < 0.02 as super::util::floatX {
1861        *num_literal_contexts = 2usize;
1862        *literal_context_map = &kStaticContextMapSimpleUTF8[..];
1863    } else {
1864        *num_literal_contexts = 3usize;
1865        *literal_context_map = &kStaticContextMapContinuation[..];
1866    }
1867}
1868
1869static kStaticContextMapComplexUTF8: [u32; 64] = [
1870    11, 11, 12, 12, /* 0 special */
1871    0, 0, 0, 0, /* 4 lf */
1872    1, 1, 9, 9, /* 8 space */
1873    2, 2, 2, 2, /* !, first after space/lf and after something else. */
1874    1, 1, 1, 1, /* " */
1875    8, 3, 3, 3, /* % */
1876    1, 1, 1, 1, /* ({[ */
1877    2, 2, 2, 2, /* }]) */
1878    8, 4, 4, 4, /* :; */
1879    8, 7, 4, 4, /* . */
1880    8, 0, 0, 0, /* > */
1881    3, 3, 3, 3, /* [0..9] */
1882    5, 5, 10, 5, /* [A-Z] */
1883    5, 5, 10, 5, 6, 6, 6, 6, /* [a-z] */
1884    6, 6, 6, 6,
1885];
1886/* Decide if we want to use a more complex static context map containing 13
1887context values, based on the entropy reduction of histograms over the
1888first 5 bits of literals. */
1889fn ShouldUseComplexStaticContextMap(
1890    input: &[u8],
1891    mut start_pos: usize,
1892    length: usize,
1893    mask: usize,
1894    quality: i32,
1895    size_hint: usize,
1896    num_literal_contexts: &mut usize,
1897    literal_context_map: &mut &[u32],
1898) -> bool {
1899    let _ = quality;
1900    //BROTLI_UNUSED(quality);
1901    /* Try the more complex static context map only for long data. */
1902    if (size_hint < (1 << 20)) {
1903        false
1904    } else {
1905        let end_pos = start_pos + length;
1906        /* To make entropy calculations faster and to fit on the stack, we collect
1907        histograms over the 5 most significant bits of literals. One histogram
1908        without context and 13 additional histograms for each context value. */
1909        let mut combined_histo: [u32; 32] = [0; 32];
1910        let mut context_histo: [[u32; 32]; 13] = [[0; 32]; 13];
1911        let mut total = 0u32;
1912        let mut entropy = [0.0 as super::util::floatX; 3];
1913        let mut dummy = 0usize;
1914        let utf8_lut = BROTLI_CONTEXT_LUT(ContextType::CONTEXT_UTF8);
1915        while start_pos + 64 <= end_pos {
1916            let stride_end_pos = start_pos + 64;
1917            let mut prev2 = input[start_pos & mask];
1918            let mut prev1 = input[(start_pos + 1) & mask];
1919
1920            /* To make the analysis of the data faster we only examine 64 byte long
1921            strides at every 4kB intervals. */
1922            for pos in start_pos + 2..stride_end_pos {
1923                let literal = input[pos & mask];
1924                let context = kStaticContextMapComplexUTF8
1925                    [BROTLI_CONTEXT(prev1, prev2, utf8_lut) as usize]
1926                    as u8;
1927                total += 1;
1928                combined_histo[(literal >> 3) as usize] += 1;
1929                context_histo[context as usize][(literal >> 3) as usize] += 1;
1930                prev2 = prev1;
1931                prev1 = literal;
1932            }
1933            start_pos += 4096;
1934        }
1935        entropy[1] = ShannonEntropy(&combined_histo[..], 32, &mut dummy);
1936        entropy[2] = 0.0 as super::util::floatX;
1937        for i in 0..13 {
1938            assert!(i < 13);
1939            entropy[2] += ShannonEntropy(&context_histo[i][..], 32, &mut dummy);
1940        }
1941        entropy[0] = (1.0 as super::util::floatX) / (total as super::util::floatX);
1942        entropy[1] *= entropy[0];
1943        entropy[2] *= entropy[0];
1944        /* The triggering heuristics below were tuned by compressing the individual
1945        files of the silesia corpus. If we skip this kind of context modeling
1946        for not very well compressible input (i.e. entropy using context modeling
1947        is 60% of maximal entropy) or if expected savings by symbol are less
1948        than 0.2 bits, then in every case when it triggers, the final compression
1949        ratio is improved. Note however that this heuristics might be too strict
1950        for some cases and could be tuned further. */
1951        if (entropy[2] > 3.0 || entropy[1] - entropy[2] < 0.2) {
1952            false
1953        } else {
1954            *num_literal_contexts = 13;
1955            *literal_context_map = &kStaticContextMapComplexUTF8;
1956            true
1957        }
1958    }
1959}
1960
1961fn DecideOverLiteralContextModeling(
1962    input: &[u8],
1963    mut start_pos: usize,
1964    length: usize,
1965    mask: usize,
1966    quality: i32,
1967    size_hint: usize,
1968    num_literal_contexts: &mut usize,
1969    literal_context_map: &mut &[u32],
1970) {
1971    if quality < 5i32 || length < 64usize {
1972    } else if ShouldUseComplexStaticContextMap(
1973        input,
1974        start_pos,
1975        length,
1976        mask,
1977        quality,
1978        size_hint,
1979        num_literal_contexts,
1980        literal_context_map,
1981    ) {
1982    } else {
1983        let end_pos: usize = start_pos.wrapping_add(length);
1984        let mut bigram_prefix_histo = [0u32; 9];
1985        while start_pos.wrapping_add(64) <= end_pos {
1986            {
1987                static lut: [i32; 4] = [0, 0, 1, 2];
1988                let stride_end_pos: usize = start_pos.wrapping_add(64);
1989                let mut prev: i32 = lut[(input[(start_pos & mask)] as i32 >> 6) as usize] * 3i32;
1990                let mut pos: usize;
1991                pos = start_pos.wrapping_add(1);
1992                while pos < stride_end_pos {
1993                    {
1994                        let literal: u8 = input[(pos & mask)];
1995                        {
1996                            let _rhs = 1;
1997                            let cur_ind = (prev + lut[(literal as i32 >> 6) as usize]);
1998                            let _lhs = &mut bigram_prefix_histo[cur_ind as usize];
1999                            *_lhs = (*_lhs).wrapping_add(_rhs as u32);
2000                        }
2001                        prev = lut[(literal as i32 >> 6) as usize] * 3i32;
2002                    }
2003                    pos = pos.wrapping_add(1);
2004                }
2005            }
2006            start_pos = start_pos.wrapping_add(4096);
2007        }
2008        ChooseContextMap(
2009            quality,
2010            &mut bigram_prefix_histo[..],
2011            num_literal_contexts,
2012            literal_context_map,
2013        );
2014    }
2015}
2016fn WriteMetaBlockInternal<Alloc: BrotliAlloc, Cb>(
2017    alloc: &mut Alloc,
2018    data: &[u8],
2019    mask: usize,
2020    last_flush_pos: u64,
2021    bytes: usize,
2022    mut is_last: bool,
2023    literal_context_mode: ContextType,
2024    params: &BrotliEncoderParams,
2025    lit_scratch_space: &mut <HistogramLiteral as CostAccessors>::i32vec,
2026    cmd_scratch_space: &mut <HistogramCommand as CostAccessors>::i32vec,
2027    dst_scratch_space: &mut <HistogramDistance as CostAccessors>::i32vec,
2028    prev_byte: u8,
2029    prev_byte2: u8,
2030    num_literals: usize,
2031    num_commands: usize,
2032    commands: &mut [Command],
2033    saved_dist_cache: &[i32; kNumDistanceCacheEntries],
2034    dist_cache: &mut [i32; 16],
2035    recoder_state: &mut RecoderState,
2036    storage_ix: &mut usize,
2037    storage: &mut [u8],
2038    cb: &mut Cb,
2039) where
2040    Cb: FnMut(
2041        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2042        &mut [interface::StaticCommand],
2043        interface::InputPair,
2044        &mut Alloc,
2045    ),
2046{
2047    let actual_is_last = is_last;
2048    if params.appendable {
2049        is_last = false;
2050    } else {
2051        assert!(!params.catable); // Sanitize Params senforces this constraint
2052    }
2053    let wrapped_last_flush_pos: u32 = WrapPosition(last_flush_pos);
2054
2055    let literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
2056    let mut block_params = params.clone();
2057    if bytes == 0usize {
2058        BrotliWriteBits(2usize, 3, storage_ix, storage);
2059        *storage_ix = storage_ix.wrapping_add(7u32 as usize) & !7u32 as usize;
2060        return;
2061    }
2062    if ShouldCompress(
2063        data,
2064        mask,
2065        last_flush_pos,
2066        bytes,
2067        num_literals,
2068        num_commands,
2069    ) == 0
2070    {
2071        dist_cache[..4].clone_from_slice(&saved_dist_cache[..4]);
2072        BrotliStoreUncompressedMetaBlock(
2073            alloc,
2074            is_last as i32,
2075            data,
2076            wrapped_last_flush_pos as usize,
2077            mask,
2078            params,
2079            bytes,
2080            recoder_state,
2081            storage_ix,
2082            storage,
2083            false,
2084            cb,
2085        );
2086        if actual_is_last != is_last {
2087            BrotliWriteEmptyLastMetaBlock(storage_ix, storage)
2088        }
2089        return;
2090    }
2091    let saved_byte_location = (*storage_ix) >> 3;
2092    let last_bytes: u16 =
2093        ((storage[saved_byte_location + 1] as u16) << 8) | storage[saved_byte_location] as u16;
2094    let last_bytes_bits: u8 = *storage_ix as u8;
2095    /*if params.dist.num_direct_distance_codes != 0 ||
2096                      params.dist.distance_postfix_bits != 0 {
2097      RecomputeDistancePrefixes(commands,
2098                                num_commands,
2099                                params.dist.num_direct_distance_codes,
2100                                params.dist.distance_postfix_bits);
2101    }*/
2102    // why was this removed??
2103    if params.quality <= 2i32 {
2104        BrotliStoreMetaBlockFast(
2105            alloc,
2106            data,
2107            wrapped_last_flush_pos as usize,
2108            bytes,
2109            mask,
2110            is_last as i32,
2111            params,
2112            saved_dist_cache,
2113            commands,
2114            num_commands,
2115            recoder_state,
2116            storage_ix,
2117            storage,
2118            cb,
2119        );
2120    } else if params.quality < 4i32 {
2121        BrotliStoreMetaBlockTrivial(
2122            alloc,
2123            data,
2124            wrapped_last_flush_pos as usize,
2125            bytes,
2126            mask,
2127            is_last as i32,
2128            params,
2129            saved_dist_cache,
2130            commands,
2131            num_commands,
2132            recoder_state,
2133            storage_ix,
2134            storage,
2135            cb,
2136        );
2137    } else {
2138        //let mut literal_context_mode: ContextType = ContextType::CONTEXT_UTF8;
2139
2140        let mut mb = MetaBlockSplit::<Alloc>::new();
2141        if params.quality < 10i32 {
2142            let mut num_literal_contexts: usize = 1;
2143            let mut literal_context_map: &[u32] = &[];
2144            if params.disable_literal_context_modeling == 0 {
2145                DecideOverLiteralContextModeling(
2146                    data,
2147                    wrapped_last_flush_pos as usize,
2148                    bytes,
2149                    mask,
2150                    params.quality,
2151                    params.size_hint,
2152                    &mut num_literal_contexts,
2153                    &mut literal_context_map,
2154                );
2155            }
2156            BrotliBuildMetaBlockGreedy(
2157                alloc,
2158                data,
2159                wrapped_last_flush_pos as usize,
2160                mask,
2161                prev_byte,
2162                prev_byte2,
2163                literal_context_mode,
2164                literal_context_lut,
2165                num_literal_contexts,
2166                literal_context_map,
2167                commands,
2168                num_commands,
2169                &mut mb,
2170            );
2171        } else {
2172            BrotliBuildMetaBlock(
2173                alloc,
2174                data,
2175                wrapped_last_flush_pos as usize,
2176                mask,
2177                &mut block_params,
2178                prev_byte,
2179                prev_byte2,
2180                commands,
2181                num_commands,
2182                literal_context_mode,
2183                lit_scratch_space,
2184                cmd_scratch_space,
2185                dst_scratch_space,
2186                &mut mb,
2187            );
2188        }
2189        if params.quality >= 4i32 {
2190            let mut num_effective_dist_codes = block_params.dist.alphabet_size;
2191            if num_effective_dist_codes > BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS as u32 {
2192                num_effective_dist_codes = BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS as u32;
2193            }
2194            BrotliOptimizeHistograms(num_effective_dist_codes as usize, &mut mb);
2195        }
2196        BrotliStoreMetaBlock(
2197            alloc,
2198            data,
2199            wrapped_last_flush_pos as usize,
2200            bytes,
2201            mask,
2202            prev_byte,
2203            prev_byte2,
2204            is_last as i32,
2205            &block_params,
2206            literal_context_mode,
2207            saved_dist_cache,
2208            commands,
2209            num_commands,
2210            &mut mb,
2211            recoder_state,
2212            storage_ix,
2213            storage,
2214            cb,
2215        );
2216        mb.destroy(alloc);
2217    }
2218    if bytes + 4 + saved_byte_location < (*storage_ix >> 3) {
2219        dist_cache[..4].clone_from_slice(&saved_dist_cache[..4]);
2220        //memcpy(dist_cache,
2221        //     saved_dist_cache,
2222        //     (4usize).wrapping_mul(::core::mem::size_of::<i32>()));
2223        storage[saved_byte_location] = last_bytes as u8;
2224        storage[saved_byte_location + 1] = (last_bytes >> 8) as u8;
2225        *storage_ix = last_bytes_bits as usize;
2226        BrotliStoreUncompressedMetaBlock(
2227            alloc,
2228            is_last as i32,
2229            data,
2230            wrapped_last_flush_pos as usize,
2231            mask,
2232            params,
2233            bytes,
2234            recoder_state,
2235            storage_ix,
2236            storage,
2237            true,
2238            cb,
2239        );
2240    }
2241    if actual_is_last != is_last {
2242        BrotliWriteEmptyLastMetaBlock(storage_ix, storage)
2243    }
2244}
2245
2246fn ChooseDistanceParams(params: &mut BrotliEncoderParams) {
2247    let mut num_direct_distance_codes = 0u32;
2248    let mut distance_postfix_bits = 0u32;
2249
2250    if params.quality >= 4 {
2251        if params.mode == BrotliEncoderMode::BROTLI_MODE_FONT {
2252            distance_postfix_bits = 1;
2253            num_direct_distance_codes = 12;
2254        } else {
2255            distance_postfix_bits = params.dist.distance_postfix_bits;
2256            num_direct_distance_codes = params.dist.num_direct_distance_codes;
2257        }
2258        let ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0f;
2259        if distance_postfix_bits > BROTLI_MAX_NPOSTFIX as u32
2260            || num_direct_distance_codes > BROTLI_MAX_NDIRECT as u32
2261            || (ndirect_msb << distance_postfix_bits) != num_direct_distance_codes
2262        {
2263            distance_postfix_bits = 0;
2264            num_direct_distance_codes = 0;
2265        }
2266    }
2267    BrotliInitDistanceParams(params, distance_postfix_bits, num_direct_distance_codes);
2268    /*(
2269    if (params.large_window) {
2270        max_distance = BROTLI_MAX_ALLOWED_DISTANCE;
2271        if (num_direct_distance_codes != 0 || distance_postfix_bits != 0) {
2272            max_distance = (3 << 29) - 4;
2273        }
2274        alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
2275            num_direct_distance_codes, distance_postfix_bits,
2276            BROTLI_LARGE_MAX_DISTANCE_BITS);
2277    } else {
2278        alphabet_size = BROTLI_DISTANCE_ALPHABET_SIZE(
2279            num_direct_distance_codes, distance_postfix_bits,
2280            BROTLI_MAX_DISTANCE_BITS);
2281
2282    }
2283
2284    params.dist.num_direct_distance_codes = num_direct_distance_codes;
2285    params.dist.distance_postfix_bits = distance_postfix_bits;
2286    params.dist.alphabet_size = alphabet_size;
2287    params.dist.max_distance = max_distance;*/
2288}
2289
2290fn EncodeData<Alloc: BrotliAlloc, MetablockCallback>(
2291    s: &mut BrotliEncoderStateStruct<Alloc>,
2292    is_last: bool,
2293    force_flush: bool,
2294    out_size: &mut usize,
2295    callback: &mut MetablockCallback,
2296    // mut output: &'a mut &'a mut [u8]
2297) -> i32
2298where
2299    MetablockCallback: FnMut(
2300        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2301        &mut [interface::StaticCommand],
2302        interface::InputPair,
2303        &mut Alloc,
2304    ),
2305{
2306    let mut delta: u64 = UnprocessedInputSize(s);
2307    let mut bytes: u32 = delta as u32;
2308    let mask = s.ringbuffer_.mask_;
2309    if EnsureInitialized(s) == 0 {
2310        return 0i32;
2311    }
2312    let dictionary = BrotliGetDictionary();
2313    if s.is_last_block_emitted_ {
2314        return 0i32;
2315    }
2316    if is_last {
2317        s.is_last_block_emitted_ = true;
2318    }
2319    if delta > InputBlockSize(s) as u64 {
2320        return 0i32;
2321    }
2322    let mut storage_ix: usize = usize::from(s.last_bytes_bits_);
2323    {
2324        let meta_size = core::cmp::max(
2325            bytes as usize,
2326            s.input_pos_.wrapping_sub(s.last_flush_pos_) as usize,
2327        );
2328        GetBrotliStorage(s, (2usize).wrapping_mul(meta_size).wrapping_add(503 + 24));
2329    }
2330    {
2331        s.storage_.slice_mut()[0] = s.last_bytes_ as u8;
2332        s.storage_.slice_mut()[1] = (s.last_bytes_ >> 8) as u8;
2333    }
2334    let mut catable_header_size = 0;
2335    if let IsFirst::NothingWritten = s.is_first_mb {
2336        if s.params.magic_number {
2337            BrotliWriteMetadataMetaBlock(&s.params, &mut storage_ix, s.storage_.slice_mut());
2338            s.last_bytes_ = s.storage_.slice()[(storage_ix >> 3)] as u16
2339                | ((s.storage_.slice()[1 + (storage_ix >> 3)] as u16) << 8);
2340            s.last_bytes_bits_ = (storage_ix & 7u32 as usize) as u8;
2341            s.next_out_ = NextOut::DynamicStorage(0);
2342            catable_header_size = storage_ix >> 3;
2343            *out_size = catable_header_size;
2344            s.is_first_mb = IsFirst::HeaderWritten;
2345        }
2346    }
2347    if let IsFirst::BothCatableBytesWritten = s.is_first_mb {
2348        // nothing to do here, move along
2349    } else if !s.params.catable {
2350        s.is_first_mb = IsFirst::BothCatableBytesWritten;
2351    } else if bytes != 0 {
2352        assert!(s.last_processed_pos_ < 2 || s.custom_dictionary);
2353        let num_bytes_to_write_uncompressed: usize = core::cmp::min(2, bytes as usize);
2354        {
2355            let data = &mut s.ringbuffer_.data_mo.slice_mut()[s.ringbuffer_.buffer_index..];
2356            BrotliStoreUncompressedMetaBlock(
2357                &mut s.m8,
2358                0,
2359                data,
2360                s.last_flush_pos_ as usize,
2361                mask as usize,
2362                &s.params,
2363                num_bytes_to_write_uncompressed,
2364                &mut s.recoder_state,
2365                &mut storage_ix,
2366                s.storage_.slice_mut(),
2367                false, /* suppress meta-block logging */
2368                callback,
2369            );
2370            s.last_bytes_ = s.storage_.slice()[(storage_ix >> 3)] as u16
2371                | ((s.storage_.slice()[1 + (storage_ix >> 3)] as u16) << 8);
2372            s.last_bytes_bits_ = (storage_ix & 7u32 as usize) as u8;
2373            s.prev_byte2_ = s.prev_byte_;
2374            s.prev_byte_ = data[s.last_flush_pos_ as usize & mask as usize];
2375            if num_bytes_to_write_uncompressed == 2 {
2376                s.prev_byte2_ = s.prev_byte_;
2377                s.prev_byte_ = data[(s.last_flush_pos_ + 1) as usize & mask as usize];
2378            }
2379        }
2380        s.last_flush_pos_ += num_bytes_to_write_uncompressed as u64;
2381        bytes -= num_bytes_to_write_uncompressed as u32;
2382        s.last_processed_pos_ += num_bytes_to_write_uncompressed as u64;
2383        if num_bytes_to_write_uncompressed >= 2 {
2384            s.is_first_mb = IsFirst::BothCatableBytesWritten;
2385        } else if num_bytes_to_write_uncompressed == 1 {
2386            if let IsFirst::FirstCatableByteWritten = s.is_first_mb {
2387                s.is_first_mb = IsFirst::BothCatableBytesWritten;
2388            } else {
2389                s.is_first_mb = IsFirst::FirstCatableByteWritten;
2390            }
2391        }
2392        catable_header_size = storage_ix >> 3;
2393        s.next_out_ = NextOut::DynamicStorage(0);
2394        *out_size = catable_header_size;
2395        delta = UnprocessedInputSize(s);
2396    }
2397    let mut wrapped_last_processed_pos: u32 = WrapPosition(s.last_processed_pos_);
2398    if s.params.quality == 1i32 && s.command_buf_.slice().is_empty() {
2399        let new_buf =
2400            <Alloc as Allocator<u32>>::alloc_cell(&mut s.m8, kCompressFragmentTwoPassBlockSize);
2401        s.command_buf_ = new_buf;
2402        let new_buf8 =
2403            <Alloc as Allocator<u8>>::alloc_cell(&mut s.m8, kCompressFragmentTwoPassBlockSize);
2404        s.literal_buf_ = new_buf8;
2405    }
2406    if s.params.quality == 0i32 || s.params.quality == 1i32 {
2407        let mut table_size: usize = 0;
2408        {
2409            if delta == 0 && !is_last {
2410                *out_size = catable_header_size;
2411                return 1i32;
2412            }
2413            let data = &mut s.ringbuffer_.data_mo.slice_mut()[s.ringbuffer_.buffer_index..];
2414
2415            //s.storage_.slice_mut()[0] = (*s).last_bytes_ as u8;
2416            //        s.storage_.slice_mut()[1] = ((*s).last_bytes_ >> 8) as u8;
2417
2418            let table: &mut [i32] =
2419                GetHashTable!(s, s.params.quality, bytes as usize, &mut table_size);
2420
2421            if s.params.quality == 0i32 {
2422                BrotliCompressFragmentFast(
2423                    &mut s.m8,
2424                    &mut data[((wrapped_last_processed_pos & mask) as usize)..],
2425                    bytes as usize,
2426                    is_last as i32,
2427                    table,
2428                    table_size,
2429                    &mut s.cmd_depths_[..],
2430                    &mut s.cmd_bits_[..],
2431                    &mut s.cmd_code_numbits_,
2432                    &mut s.cmd_code_[..],
2433                    &mut storage_ix,
2434                    s.storage_.slice_mut(),
2435                );
2436            } else {
2437                BrotliCompressFragmentTwoPass(
2438                    &mut s.m8,
2439                    &mut data[((wrapped_last_processed_pos & mask) as usize)..],
2440                    bytes as usize,
2441                    is_last as i32,
2442                    s.command_buf_.slice_mut(),
2443                    s.literal_buf_.slice_mut(),
2444                    table,
2445                    table_size,
2446                    &mut storage_ix,
2447                    s.storage_.slice_mut(),
2448                );
2449            }
2450            s.last_bytes_ = s.storage_.slice()[(storage_ix >> 3)] as u16
2451                | ((s.storage_.slice()[(storage_ix >> 3) + 1] as u16) << 8);
2452            s.last_bytes_bits_ = (storage_ix & 7u32 as usize) as u8;
2453        }
2454        UpdateLastProcessedPos(s);
2455        // *output = &mut s.storage_.slice_mut();
2456        s.next_out_ = NextOut::DynamicStorage(0); // this always returns that
2457        *out_size = storage_ix >> 3;
2458        return 1i32;
2459    }
2460    {
2461        let mut newsize: usize = s
2462            .num_commands_
2463            .wrapping_add(bytes.wrapping_div(2) as usize)
2464            .wrapping_add(1);
2465        if newsize > s.cmd_alloc_size_ {
2466            newsize = newsize.wrapping_add(bytes.wrapping_div(4).wrapping_add(16) as usize);
2467            s.cmd_alloc_size_ = newsize;
2468            let mut new_commands = <Alloc as Allocator<Command>>::alloc_cell(&mut s.m8, newsize);
2469            if !s.commands_.slice().is_empty() {
2470                new_commands.slice_mut()[..s.num_commands_]
2471                    .clone_from_slice(&s.commands_.slice()[..s.num_commands_]);
2472                <Alloc as Allocator<Command>>::free_cell(
2473                    &mut s.m8,
2474                    core::mem::take(&mut s.commands_),
2475                );
2476            }
2477            s.commands_ = new_commands;
2478        }
2479    }
2480    InitOrStitchToPreviousBlock(
2481        &mut s.m8,
2482        &mut s.hasher_,
2483        &mut s.ringbuffer_.data_mo.slice_mut()[s.ringbuffer_.buffer_index..],
2484        mask as usize,
2485        &mut s.params,
2486        wrapped_last_processed_pos as usize,
2487        bytes as usize,
2488        is_last,
2489    );
2490    let literal_context_mode = ChooseContextMode(
2491        &s.params,
2492        s.ringbuffer_.data_mo.slice(),
2493        WrapPosition(s.last_flush_pos_) as usize,
2494        mask as usize,
2495        (s.input_pos_.wrapping_sub(s.last_flush_pos_)) as usize,
2496    );
2497    if s.num_commands_ != 0 && s.last_insert_len_ == 0 {
2498        ExtendLastCommand(s, &mut bytes, &mut wrapped_last_processed_pos);
2499    }
2500    if false {
2501        // we are remapping 10 as quality=9.5 since Zopfli doesn't seem to offer much benefits here
2502        panic!(
2503            r####"
2504    BrotliCreateZopfliBackwardReferences(m,
2505                                         dictionary,
2506                                         bytes as usize,
2507                                         wrapped_last_processed_pos as usize,
2508                                         data,
2509                                         mask as usize,
2510                                         &mut s.params,
2511                                         s.hasher_,
2512                                         s.dist_cache_.as_mut_ptr(),
2513                                         &mut s.last_insert_len_,
2514                                         &mut *s.commands_[((*s).num_commands_ as usize)..],
2515                                         &mut s.num_commands_,
2516                                         &mut s.num_literals_);"####
2517        );
2518    } else if false && s.params.quality == 11i32 {
2519        panic!(
2520            r####"BrotliCreateHqZopfliBackwardReferences(m,
2521                                           dictionary,
2522                                           bytes as usize,
2523                                           wrapped_last_processed_pos as usize,
2524                                           data,
2525                                           mask as usize,
2526                                           &mut s.params,
2527                                           s.hasher_,
2528                                           s.dist_cache_.as_mut_ptr(),
2529                                           &mut s.last_insert_len_,
2530                                           &mut *s.commands_[((*s).num_commands_ as usize)..],
2531                                           &mut s.num_commands_,
2532                                           &mut s.num_literals_);"####
2533        );
2534    } else {
2535        BrotliCreateBackwardReferences(
2536            &mut s.m8,
2537            dictionary,
2538            bytes as usize,
2539            wrapped_last_processed_pos as usize,
2540            &mut s.ringbuffer_.data_mo.slice_mut()[s.ringbuffer_.buffer_index..],
2541            mask as usize,
2542            &mut s.params,
2543            &mut s.hasher_,
2544            &mut s.dist_cache_,
2545            &mut s.last_insert_len_,
2546            &mut s.commands_.slice_mut()[s.num_commands_..],
2547            &mut s.num_commands_,
2548            &mut s.num_literals_,
2549        );
2550    }
2551    {
2552        let max_length: usize = MaxMetablockSize(&mut s.params);
2553        let max_literals: usize = max_length.wrapping_div(8);
2554        let max_commands: usize = max_length.wrapping_div(8);
2555        let processed_bytes: usize = s.input_pos_.wrapping_sub(s.last_flush_pos_) as usize;
2556        let next_input_fits_metablock =
2557            processed_bytes.wrapping_add(InputBlockSize(s)) <= max_length;
2558        let should_flush =
2559            s.params.quality < 4 && s.num_literals_.wrapping_add(s.num_commands_) >= 0x2fff;
2560        if !is_last
2561            && !force_flush
2562            && !should_flush
2563            && next_input_fits_metablock
2564            && s.num_literals_ < max_literals
2565            && s.num_commands_ < max_commands
2566        {
2567            if UpdateLastProcessedPos(s) {
2568                HasherReset(&mut s.hasher_);
2569            }
2570            *out_size = catable_header_size;
2571            return 1i32;
2572        }
2573    }
2574    if s.last_insert_len_ > 0usize {
2575        InitInsertCommand(
2576            &mut s.commands_.slice_mut()[s.num_commands_],
2577            s.last_insert_len_,
2578        );
2579        s.num_commands_ = s.num_commands_.wrapping_add(1);
2580        s.num_literals_ = s.num_literals_.wrapping_add(s.last_insert_len_);
2581        s.last_insert_len_ = 0usize;
2582    }
2583    if !is_last && s.input_pos_ == s.last_flush_pos_ {
2584        *out_size = catable_header_size;
2585        return 1i32;
2586    }
2587    {
2588        let metablock_size: u32 = s.input_pos_.wrapping_sub(s.last_flush_pos_) as u32;
2589        //let mut storage_ix: usize = s.last_bytes_bits_ as usize;
2590        //s.storage_.slice_mut()[0] = (*s).last_bytes_ as u8;
2591        //s.storage_.slice_mut()[1] = ((*s).last_bytes_ >> 8) as u8;
2592
2593        WriteMetaBlockInternal(
2594            &mut s.m8,
2595            &mut s.ringbuffer_.data_mo.slice_mut()[s.ringbuffer_.buffer_index..],
2596            mask as usize,
2597            s.last_flush_pos_,
2598            metablock_size as usize,
2599            is_last,
2600            literal_context_mode,
2601            &mut s.params,
2602            &mut s.literal_scratch_space,
2603            &mut s.command_scratch_space,
2604            &mut s.distance_scratch_space,
2605            s.prev_byte_,
2606            s.prev_byte2_,
2607            s.num_literals_,
2608            s.num_commands_,
2609            s.commands_.slice_mut(),
2610            &mut s.saved_dist_cache_,
2611            &mut s.dist_cache_,
2612            &mut s.recoder_state,
2613            &mut storage_ix,
2614            s.storage_.slice_mut(),
2615            callback,
2616        );
2617
2618        s.last_bytes_ = s.storage_.slice()[(storage_ix >> 3)] as u16
2619            | ((s.storage_.slice()[1 + (storage_ix >> 3)] as u16) << 8);
2620        s.last_bytes_bits_ = (storage_ix & 7u32 as usize) as u8;
2621        s.last_flush_pos_ = s.input_pos_;
2622        if UpdateLastProcessedPos(s) {
2623            HasherReset(&mut s.hasher_);
2624        }
2625        let data = &s.ringbuffer_.data_mo.slice()[s.ringbuffer_.buffer_index..];
2626        if s.last_flush_pos_ > 0 {
2627            s.prev_byte_ = data[(((s.last_flush_pos_ as u32).wrapping_sub(1) & mask) as usize)];
2628        }
2629        if s.last_flush_pos_ > 1 {
2630            s.prev_byte2_ = data[((s.last_flush_pos_.wrapping_sub(2) as u32 & mask) as usize)];
2631        }
2632        s.num_commands_ = 0usize;
2633        s.num_literals_ = 0usize;
2634        s.saved_dist_cache_
2635            .clone_from_slice(s.dist_cache_.split_at(4).0);
2636        s.next_out_ = NextOut::DynamicStorage(0); // this always returns that
2637        *out_size = storage_ix >> 3;
2638        1i32
2639    }
2640}
2641
2642fn WriteMetadataHeader<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) -> usize {
2643    let block_size = s.remaining_metadata_bytes_ as usize;
2644    let header = GetNextOut!(*s);
2645    let mut storage_ix: usize;
2646    storage_ix = s.last_bytes_bits_ as usize;
2647    header[0] = s.last_bytes_ as u8;
2648    header[1] = (s.last_bytes_ >> 8) as u8;
2649    s.last_bytes_ = 0;
2650    s.last_bytes_bits_ = 0;
2651    BrotliWriteBits(1, 0, &mut storage_ix, header);
2652    BrotliWriteBits(2usize, 3, &mut storage_ix, header);
2653    BrotliWriteBits(1, 0, &mut storage_ix, header);
2654    if block_size == 0usize {
2655        BrotliWriteBits(2usize, 0, &mut storage_ix, header);
2656    } else {
2657        let nbits: u32 = if block_size == 1 {
2658            0u32
2659        } else {
2660            Log2FloorNonZero((block_size as u32).wrapping_sub(1) as (u64)).wrapping_add(1)
2661        };
2662        let nbytes: u32 = nbits.wrapping_add(7).wrapping_div(8);
2663        BrotliWriteBits(2usize, nbytes as (u64), &mut storage_ix, header);
2664        BrotliWriteBits(
2665            (8u32).wrapping_mul(nbytes) as usize,
2666            block_size.wrapping_sub(1) as u64,
2667            &mut storage_ix,
2668            header,
2669        );
2670    }
2671    storage_ix.wrapping_add(7u32 as usize) >> 3
2672}
2673
2674fn brotli_min_uint32_t(a: u32, b: u32) -> u32 {
2675    if a < b {
2676        a
2677    } else {
2678        b
2679    }
2680}
2681fn ProcessMetadata<
2682    Alloc: BrotliAlloc,
2683    MetaBlockCallback: FnMut(
2684        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2685        &mut [interface::StaticCommand],
2686        interface::InputPair,
2687        &mut Alloc,
2688    ),
2689>(
2690    s: &mut BrotliEncoderStateStruct<Alloc>,
2691    available_in: &mut usize,
2692    next_in_array: &[u8],
2693    next_in_offset: &mut usize,
2694    available_out: &mut usize,
2695    next_out_array: &mut [u8],
2696    next_out_offset: &mut usize,
2697    total_out: &mut Option<usize>,
2698    metablock_callback: &mut MetaBlockCallback,
2699) -> i32 {
2700    if *available_in > (1u32 << 24) as usize {
2701        return 0i32;
2702    }
2703    if s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING as i32 {
2704        s.remaining_metadata_bytes_ = *available_in as u32;
2705        s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_METADATA_HEAD;
2706    }
2707    if s.stream_state_ as i32 != BrotliEncoderStreamState::BROTLI_STREAM_METADATA_HEAD as i32
2708        && (s.stream_state_ as i32 != BrotliEncoderStreamState::BROTLI_STREAM_METADATA_BODY as i32)
2709    {
2710        return 0i32;
2711    }
2712    loop {
2713        if InjectFlushOrPushOutput(s, available_out, next_out_array, next_out_offset, total_out)
2714            != 0
2715        {
2716            {
2717                continue;
2718            }
2719        }
2720        if s.available_out_ != 0usize {
2721            {
2722                break;
2723            }
2724        }
2725        if s.input_pos_ != s.last_flush_pos_ {
2726            let mut avail_out: usize = s.available_out_;
2727            let result: i32 = EncodeData(s, false, true, &mut avail_out, metablock_callback);
2728            s.available_out_ = avail_out;
2729            if result == 0 {
2730                return 0i32;
2731            }
2732            {
2733                {
2734                    continue;
2735                }
2736            }
2737        }
2738        if s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_METADATA_HEAD as i32 {
2739            s.next_out_ = NextOut::TinyBuf(0);
2740            s.available_out_ = WriteMetadataHeader(s);
2741            s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_METADATA_BODY;
2742            {
2743                {
2744                    continue;
2745                }
2746            }
2747        } else {
2748            if s.remaining_metadata_bytes_ == 0u32 {
2749                s.remaining_metadata_bytes_ = !(0u32);
2750                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING;
2751                {
2752                    {
2753                        break;
2754                    }
2755                }
2756            }
2757            if *available_out != 0 {
2758                let copy: u32 =
2759                    brotli_min_size_t(s.remaining_metadata_bytes_ as usize, *available_out) as u32;
2760                next_out_array[*next_out_offset..(*next_out_offset + copy as usize)]
2761                    .clone_from_slice(
2762                        &next_in_array[*next_in_offset..(*next_in_offset + copy as usize)],
2763                    );
2764                //memcpy(*next_out, *next_in, copy as usize);
2765                // *next_in = next_in.offset(copy as isize);
2766                *next_in_offset += copy as usize;
2767                *available_in = available_in.wrapping_sub(copy as usize);
2768                s.remaining_metadata_bytes_ = s.remaining_metadata_bytes_.wrapping_sub(copy);
2769                *next_out_offset += copy as usize;
2770                // *next_out = next_out.offset(copy as isize);
2771                *available_out = available_out.wrapping_sub(copy as usize);
2772            } else {
2773                let copy: u32 = brotli_min_uint32_t(s.remaining_metadata_bytes_, 16u32);
2774                s.next_out_ = NextOut::TinyBuf(0);
2775                GetNextOut!(s)[..(copy as usize)].clone_from_slice(
2776                    &next_in_array[*next_in_offset..(*next_in_offset + copy as usize)],
2777                );
2778                //memcpy(s.next_out_, *next_in, copy as usize);
2779                // *next_in = next_in.offset(copy as isize);
2780                *next_in_offset += copy as usize;
2781                *available_in = available_in.wrapping_sub(copy as usize);
2782                s.remaining_metadata_bytes_ = s.remaining_metadata_bytes_.wrapping_sub(copy);
2783                s.available_out_ = copy as usize;
2784            }
2785            {
2786                {
2787                    continue;
2788                }
2789            }
2790        }
2791    }
2792    1i32
2793}
2794fn CheckFlushCompleteInner(
2795    stream_state: &mut BrotliEncoderStreamState,
2796    available_out: usize,
2797    next_out: &mut NextOut,
2798) {
2799    if *stream_state == BrotliEncoderStreamState::BROTLI_STREAM_FLUSH_REQUESTED
2800        && (available_out == 0)
2801    {
2802        *stream_state = BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING;
2803        *next_out = NextOut::None;
2804    }
2805}
2806
2807fn CheckFlushComplete<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) {
2808    CheckFlushCompleteInner(&mut s.stream_state_, s.available_out_, &mut s.next_out_);
2809}
2810
2811fn BrotliEncoderCompressStreamFast<Alloc: BrotliAlloc>(
2812    s: &mut BrotliEncoderStateStruct<Alloc>,
2813    op: BrotliEncoderOperation,
2814    available_in: &mut usize,
2815    next_in_array: &[u8],
2816    next_in_offset: &mut usize,
2817    available_out: &mut usize,
2818    next_out_array: &mut [u8],
2819    next_out_offset: &mut usize,
2820    total_out: &mut Option<usize>,
2821) -> i32 {
2822    let block_size_limit: usize = 1 << s.params.lgwin;
2823    let buf_size: usize = brotli_min_size_t(
2824        kCompressFragmentTwoPassBlockSize,
2825        brotli_min_size_t(*available_in, block_size_limit),
2826    );
2827    let mut command_buf = <Alloc as Allocator<u32>>::AllocatedMemory::default();
2828    let mut literal_buf = <Alloc as Allocator<u8>>::AllocatedMemory::default();
2829    if s.params.quality != 0i32 && (s.params.quality != 1i32) {
2830        return 0i32;
2831    }
2832    if s.params.quality == 1i32 {
2833        if s.command_buf_.slice().is_empty() && (buf_size == kCompressFragmentTwoPassBlockSize) {
2834            s.command_buf_ =
2835                <Alloc as Allocator<u32>>::alloc_cell(&mut s.m8, kCompressFragmentTwoPassBlockSize);
2836            s.literal_buf_ =
2837                <Alloc as Allocator<u8>>::alloc_cell(&mut s.m8, kCompressFragmentTwoPassBlockSize);
2838        }
2839        if !s.command_buf_.slice().is_empty() {
2840            command_buf = core::mem::take(&mut s.command_buf_);
2841            literal_buf = core::mem::take(&mut s.literal_buf_);
2842        } else {
2843            command_buf = <Alloc as Allocator<u32>>::alloc_cell(&mut s.m8, buf_size);
2844            literal_buf = <Alloc as Allocator<u8>>::alloc_cell(&mut s.m8, buf_size);
2845        }
2846    }
2847    loop {
2848        if InjectFlushOrPushOutput(s, available_out, next_out_array, next_out_offset, total_out)
2849            != 0
2850        {
2851            {
2852                continue;
2853            }
2854        }
2855        if s.available_out_ == 0usize
2856            && (s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING as i32)
2857            && (*available_in != 0usize
2858                || op as i32 != BrotliEncoderOperation::BROTLI_OPERATION_PROCESS as i32)
2859        {
2860            let block_size: usize = brotli_min_size_t(block_size_limit, *available_in);
2861            let is_last = *available_in == block_size
2862                && op == BrotliEncoderOperation::BROTLI_OPERATION_FINISH;
2863            let force_flush =
2864                *available_in == block_size && op == BrotliEncoderOperation::BROTLI_OPERATION_FLUSH;
2865            let max_out_size: usize = (2usize).wrapping_mul(block_size).wrapping_add(503);
2866            let mut inplace: i32 = 1i32;
2867            let storage: &mut [u8];
2868            let mut storage_ix: usize = s.last_bytes_bits_ as usize;
2869            let mut table_size: usize = 0;
2870
2871            if force_flush && block_size == 0 {
2872                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_FLUSH_REQUESTED;
2873                {
2874                    {
2875                        continue;
2876                    }
2877                }
2878            }
2879            if max_out_size <= *available_out {
2880                storage = &mut next_out_array[*next_out_offset..]; //GetNextOut!(s);
2881            } else {
2882                inplace = 0i32;
2883                GetBrotliStorage(s, max_out_size);
2884                storage = s.storage_.slice_mut();
2885            }
2886            storage[0] = s.last_bytes_ as u8;
2887            storage[1] = (s.last_bytes_ >> 8) as u8;
2888            let table: &mut [i32] = GetHashTable!(s, s.params.quality, block_size, &mut table_size);
2889            if s.params.quality == 0i32 {
2890                BrotliCompressFragmentFast(
2891                    &mut s.m8,
2892                    &(next_in_array)[*next_in_offset..],
2893                    block_size,
2894                    is_last as i32,
2895                    table,
2896                    table_size,
2897                    &mut s.cmd_depths_[..],
2898                    &mut s.cmd_bits_[..],
2899                    &mut s.cmd_code_numbits_,
2900                    &mut s.cmd_code_[..],
2901                    &mut storage_ix,
2902                    storage,
2903                );
2904            } else {
2905                BrotliCompressFragmentTwoPass(
2906                    &mut s.m8,
2907                    &(next_in_array)[*next_in_offset..],
2908                    block_size,
2909                    is_last as i32,
2910                    command_buf.slice_mut(),
2911                    literal_buf.slice_mut(),
2912                    table,
2913                    table_size,
2914                    &mut storage_ix,
2915                    storage,
2916                );
2917            }
2918            *next_in_offset += block_size;
2919            *available_in = available_in.wrapping_sub(block_size);
2920            if inplace != 0 {
2921                let out_bytes: usize = storage_ix >> 3;
2922                0i32;
2923                0i32;
2924                *next_out_offset += out_bytes;
2925                *available_out = available_out.wrapping_sub(out_bytes);
2926                s.total_out_ = s.total_out_.wrapping_add(out_bytes as u64);
2927                if let &mut Some(ref mut total_out_inner) = total_out {
2928                    *total_out_inner = s.total_out_ as usize;
2929                }
2930            } else {
2931                let out_bytes: usize = storage_ix >> 3;
2932                s.next_out_ = NextOut::DynamicStorage(0);
2933                s.available_out_ = out_bytes;
2934            }
2935            s.last_bytes_ =
2936                storage[(storage_ix >> 3)] as u16 | ((storage[1 + (storage_ix >> 3)] as u16) << 8);
2937            s.last_bytes_bits_ = (storage_ix & 7u32 as usize) as u8;
2938            if force_flush {
2939                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_FLUSH_REQUESTED;
2940            }
2941            if is_last {
2942                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_FINISHED;
2943            }
2944            {
2945                {
2946                    continue;
2947                }
2948            }
2949        }
2950        {
2951            {
2952                break;
2953            }
2954        }
2955    }
2956    if command_buf.slice().len() == kCompressFragmentTwoPassBlockSize
2957        && s.command_buf_.slice().is_empty()
2958    {
2959        // undo temporary aliasing of command_buf and literal_buf
2960        s.command_buf_ = core::mem::take(&mut command_buf);
2961        s.literal_buf_ = core::mem::take(&mut literal_buf);
2962    } else {
2963        <Alloc as Allocator<u32>>::free_cell(&mut s.m8, command_buf);
2964        <Alloc as Allocator<u8>>::free_cell(&mut s.m8, literal_buf);
2965    }
2966    CheckFlushComplete(s);
2967    1i32
2968}
2969fn RemainingInputBlockSize<Alloc: BrotliAlloc>(s: &mut BrotliEncoderStateStruct<Alloc>) -> usize {
2970    let delta: u64 = UnprocessedInputSize(s);
2971    let block_size: usize = InputBlockSize(s);
2972    if delta >= block_size as u64 {
2973        return 0usize;
2974    }
2975    (block_size as u64).wrapping_sub(delta) as usize
2976}
2977
2978pub fn BrotliEncoderCompressStream<
2979    Alloc: BrotliAlloc,
2980    MetablockCallback: FnMut(
2981        &mut interface::PredictionModeContextMap<InputReferenceMut>,
2982        &mut [interface::StaticCommand],
2983        interface::InputPair,
2984        &mut Alloc,
2985    ),
2986>(
2987    s: &mut BrotliEncoderStateStruct<Alloc>,
2988    op: BrotliEncoderOperation,
2989    available_in: &mut usize,
2990    next_in_array: &[u8],
2991    next_in_offset: &mut usize,
2992    available_out: &mut usize,
2993    next_out_array: &mut [u8],
2994    next_out_offset: &mut usize,
2995    total_out: &mut Option<usize>,
2996    metablock_callback: &mut MetablockCallback,
2997) -> i32 {
2998    if EnsureInitialized(s) == 0 {
2999        return 0i32;
3000    }
3001    if s.remaining_metadata_bytes_ != !(0u32) {
3002        if *available_in != s.remaining_metadata_bytes_ as usize {
3003            return 0i32;
3004        }
3005        if op as i32 != BrotliEncoderOperation::BROTLI_OPERATION_EMIT_METADATA as i32 {
3006            return 0i32;
3007        }
3008    }
3009    if op as i32 == BrotliEncoderOperation::BROTLI_OPERATION_EMIT_METADATA as i32 {
3010        UpdateSizeHint(s, 0usize);
3011        return ProcessMetadata(
3012            s,
3013            available_in,
3014            next_in_array,
3015            next_in_offset,
3016            available_out,
3017            next_out_array,
3018            next_out_offset,
3019            total_out,
3020            metablock_callback,
3021        );
3022    }
3023    if s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_METADATA_HEAD as i32
3024        || s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_METADATA_BODY as i32
3025    {
3026        return 0i32;
3027    }
3028    if s.stream_state_ as i32 != BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING as i32
3029        && (*available_in != 0usize)
3030    {
3031        return 0i32;
3032    }
3033    if (s.params.quality == 0i32 || s.params.quality == 1i32) && !s.params.catable {
3034        // this part of the code does not support concatability
3035        return BrotliEncoderCompressStreamFast(
3036            s,
3037            op,
3038            available_in,
3039            next_in_array,
3040            next_in_offset,
3041            available_out,
3042            next_out_array,
3043            next_out_offset,
3044            total_out,
3045        );
3046    }
3047    loop {
3048        let remaining_block_size: usize = RemainingInputBlockSize(s);
3049        if remaining_block_size != 0usize && (*available_in != 0usize) {
3050            let copy_input_size: usize = brotli_min_size_t(remaining_block_size, *available_in);
3051            CopyInputToRingBuffer(s, copy_input_size, &next_in_array[*next_in_offset..]);
3052            *next_in_offset += copy_input_size;
3053            *available_in = available_in.wrapping_sub(copy_input_size);
3054            {
3055                {
3056                    continue;
3057                }
3058            }
3059        }
3060        if InjectFlushOrPushOutput(s, available_out, next_out_array, next_out_offset, total_out)
3061            != 0
3062        {
3063            {
3064                continue;
3065            }
3066        }
3067        if s.available_out_ == 0usize
3068            && (s.stream_state_ as i32 == BrotliEncoderStreamState::BROTLI_STREAM_PROCESSING as i32)
3069            && (remaining_block_size == 0usize
3070                || op as i32 != BrotliEncoderOperation::BROTLI_OPERATION_PROCESS as i32)
3071        {
3072            let is_last =
3073                *available_in == 0 && op == BrotliEncoderOperation::BROTLI_OPERATION_FINISH;
3074            let force_flush =
3075                *available_in == 0 && op == BrotliEncoderOperation::BROTLI_OPERATION_FLUSH;
3076
3077            UpdateSizeHint(s, *available_in);
3078            let mut avail_out = s.available_out_;
3079            let result: i32 =
3080                EncodeData(s, is_last, force_flush, &mut avail_out, metablock_callback);
3081            s.available_out_ = avail_out;
3082            //this function set next_out to &storage[0]
3083            if result == 0 {
3084                return 0i32;
3085            }
3086            if force_flush {
3087                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_FLUSH_REQUESTED;
3088            }
3089            if is_last {
3090                s.stream_state_ = BrotliEncoderStreamState::BROTLI_STREAM_FINISHED;
3091            }
3092            {
3093                {
3094                    continue;
3095                }
3096            }
3097        }
3098        {
3099            {
3100                break;
3101            }
3102        }
3103    }
3104    CheckFlushComplete(s);
3105    1i32
3106}
3107
3108pub fn BrotliEncoderIsFinished<Alloc: BrotliAlloc>(s: &BrotliEncoderStateStruct<Alloc>) -> i32 {
3109    if s.stream_state_ == BrotliEncoderStreamState::BROTLI_STREAM_FINISHED
3110        && BrotliEncoderHasMoreOutput(s) == 0
3111    {
3112        1i32
3113    } else {
3114        0i32
3115    }
3116}
3117
3118pub fn BrotliEncoderHasMoreOutput<Alloc: BrotliAlloc>(s: &BrotliEncoderStateStruct<Alloc>) -> i32 {
3119    if s.available_out_ != 0 {
3120        1i32
3121    } else {
3122        0i32
3123    }
3124}
3125
3126pub fn BrotliEncoderTakeOutput<'a, Alloc: BrotliAlloc>(
3127    s: &'a mut BrotliEncoderStateStruct<Alloc>,
3128    size: &mut usize,
3129) -> &'a [u8] {
3130    let mut consumed_size: usize = s.available_out_;
3131    let mut result: &[u8] = GetNextOut!(*s);
3132    if *size != 0 {
3133        consumed_size = brotli_min_size_t(*size, s.available_out_);
3134    }
3135    if consumed_size != 0 {
3136        s.next_out_ = NextOutIncrement(&s.next_out_, consumed_size as i32);
3137        s.available_out_ = s.available_out_.wrapping_sub(consumed_size);
3138        s.total_out_ = s.total_out_.wrapping_add(consumed_size as u64);
3139        CheckFlushCompleteInner(&mut s.stream_state_, s.available_out_, &mut s.next_out_);
3140        *size = consumed_size;
3141    } else {
3142        *size = 0usize;
3143        result = &[];
3144    }
3145    result
3146}
3147
3148pub fn BrotliEncoderVersion() -> u32 {
3149    0x1000f01u32
3150}
3151
3152pub fn BrotliEncoderInputBlockSize<Alloc: BrotliAlloc>(
3153    s: &mut BrotliEncoderStateStruct<Alloc>,
3154) -> usize {
3155    InputBlockSize(s)
3156}
3157
3158pub fn BrotliEncoderCopyInputToRingBuffer<Alloc: BrotliAlloc>(
3159    s: &mut BrotliEncoderStateStruct<Alloc>,
3160    input_size: usize,
3161    input_buffer: &[u8],
3162) {
3163    CopyInputToRingBuffer(s, input_size, input_buffer);
3164}
3165
3166pub fn BrotliEncoderWriteData<
3167    'a,
3168    Alloc: BrotliAlloc,
3169    MetablockCallback: FnMut(
3170        &mut interface::PredictionModeContextMap<InputReferenceMut>,
3171        &mut [interface::StaticCommand],
3172        interface::InputPair,
3173        &mut Alloc,
3174    ),
3175>(
3176    s: &'a mut BrotliEncoderStateStruct<Alloc>,
3177    is_last: i32,
3178    force_flush: i32,
3179    out_size: &mut usize,
3180    output: &'a mut &'a mut [u8],
3181    metablock_callback: &mut MetablockCallback,
3182) -> i32 {
3183    let ret = EncodeData(
3184        s,
3185        is_last != 0,
3186        force_flush != 0,
3187        out_size,
3188        metablock_callback,
3189    );
3190    *output = s.storage_.slice_mut();
3191    ret
3192}