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;
49static 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, 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 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}
355pub 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
369pub 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 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, 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 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}
535fn 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 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 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 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(¶ms.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(¶ms.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(¶ms.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(¶ms.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(¶ms.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(¶ms.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(¶ms.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(¶ms.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(¶ms.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 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 InitializeH6(m, params)
1184
1185 }
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 ChooseHasher(&mut (*params));
1216 *handle = BrotliMakeHasher(m16, params);
1219 handle.GetHasherCommon().params = params.hasher;
1220 HasherReset(handle); 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; s.params.appendable = true; 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
1421fn ChooseContextMode(
1423 params: &BrotliEncoderParams,
1424 data: &[u8],
1425 pos: usize,
1426 mask: usize,
1427 length: usize,
1428) -> ContextType {
1429 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 *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 {
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 }
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, 0, 0, 0, 1, 1, 9, 9, 2, 2, 2, 2, 1, 1, 1, 1, 8, 3, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 8, 4, 4, 4, 8, 7, 4, 4, 8, 0, 0, 0, 3, 3, 3, 3, 5, 5, 10, 5, 5, 5, 10, 5, 6, 6, 6, 6, 6, 6, 6, 6,
1885];
1886fn 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 if (size_hint < (1 << 20)) {
1903 false
1904 } else {
1905 let end_pos = start_pos + length;
1906 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 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 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); }
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.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 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 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 }
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 ) -> 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 } 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, 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 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 s.next_out_ = NextOut::DynamicStorage(0); *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 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 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); *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 *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 *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 *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..]; } 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 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 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 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}