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