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