use core;
use core::cmp::min;
use super::super::alloc;
use super::backward_references::kHashMul32;
use super::bit_cost::BitsEntropy;
use super::brotli_bit_stream::{BrotliBuildAndStoreHuffmanTreeFast, BrotliStoreHuffmanTree};
use super::entropy_encode::{
BrotliConvertBitDepthsToSymbols, BrotliCreateHuffmanTree, HuffmanTree,
};
use super::static_dict::{
FindMatchLengthWithLimit, BROTLI_UNALIGNED_LOAD32, BROTLI_UNALIGNED_LOAD64,
BROTLI_UNALIGNED_STORE64,
};
use super::util::{floatX, Log2FloorNonZero};
static kCompressFragmentTwoPassBlockSize: usize = (1i32 << 17) as usize;
fn EmitInsertLen(insertlen: u32, commands: &mut &mut [u32]) -> usize {
if insertlen < 6u32 {
(*commands)[0] = insertlen;
} else if insertlen < 130u32 {
let tail: u32 = insertlen.wrapping_sub(2);
let nbits: u32 = Log2FloorNonZero(tail as (u64)).wrapping_sub(1);
let prefix: u32 = tail >> nbits;
let inscode: u32 = (nbits << 1).wrapping_add(prefix).wrapping_add(2);
let extra: u32 = tail.wrapping_sub(prefix << nbits);
(*commands)[0] = inscode | extra << 8;
} else if insertlen < 2114u32 {
let tail: u32 = insertlen.wrapping_sub(66);
let nbits: u32 = Log2FloorNonZero(tail as (u64));
let code: u32 = nbits.wrapping_add(10);
let extra: u32 = tail.wrapping_sub(1u32 << nbits);
(*commands)[0] = code | extra << 8;
} else if insertlen < 6210u32 {
let extra: u32 = insertlen.wrapping_sub(2114);
(*commands)[0] = 21u32 | extra << 8;
} else if insertlen < 22594u32 {
let extra: u32 = insertlen.wrapping_sub(6210);
(*commands)[0] = 22u32 | extra << 8;
} else {
let extra: u32 = insertlen.wrapping_sub(22594);
(*commands)[0] = 23u32 | extra << 8;
}
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
1
}
fn EmitDistance(distance: u32, commands: &mut &mut [u32]) -> usize {
let d: u32 = distance.wrapping_add(3);
let nbits: u32 = Log2FloorNonZero(d as (u64)).wrapping_sub(1);
let prefix: u32 = d >> nbits & 1u32;
let offset: u32 = (2u32).wrapping_add(prefix) << nbits;
let distcode: u32 = (2u32)
.wrapping_mul(nbits.wrapping_sub(1))
.wrapping_add(prefix)
.wrapping_add(80);
let extra: u32 = d.wrapping_sub(offset);
(*commands)[0] = distcode | extra << 8;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
1
}
fn EmitCopyLenLastDistance(copylen: usize, commands: &mut &mut [u32]) -> usize {
if copylen < 12usize {
(*commands)[0] = copylen.wrapping_add(20) as u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
1
} else if copylen < 72usize {
let tail: usize = copylen.wrapping_sub(8);
let nbits: usize = Log2FloorNonZero(tail as u64).wrapping_sub(1) as usize;
let prefix: usize = tail >> nbits;
let code: usize = (nbits << 1).wrapping_add(prefix).wrapping_add(28);
let extra: usize = tail.wrapping_sub(prefix << nbits);
(*commands)[0] = (code | extra << 8) as u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
1
} else if copylen < 136usize {
let tail: usize = copylen.wrapping_sub(8);
let code: usize = (tail >> 5).wrapping_add(54);
let extra: usize = tail & 31usize;
(*commands)[0] = (code | extra << 8) as u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
(*commands)[0] = 64u32;
let remainder2 = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder2[1..]);
2
} else if copylen < 2120usize {
let tail: usize = copylen.wrapping_sub(72);
let nbits: usize = Log2FloorNonZero(tail as u64) as usize;
let code: usize = nbits.wrapping_add(52);
let extra: usize = tail.wrapping_sub(1usize << nbits);
(*commands)[0] = (code | extra << 8) as u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
(*commands)[0] = 64u32;
let remainder2 = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder2[1..]);
2
} else {
let extra: usize = copylen.wrapping_sub(2120);
(*commands)[0] = (63usize | extra << 8) as u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
(*commands)[0] = 64u32;
let remainder2 = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder2[1..]);
2
}
}
fn HashBytesAtOffset(v: u64, offset: i32, shift: usize, length: usize) -> u32 {
let h: u64 = (v >> (8i32 * offset) << ((8 - length) * 8)).wrapping_mul(kHashMul32 as (u64));
(h >> shift) as u32
}
fn EmitCopyLen(copylen: usize, commands: &mut &mut [u32]) -> usize {
if copylen < 10usize {
(*commands)[0] = copylen.wrapping_add(38) as u32;
} else if copylen < 134usize {
let tail: usize = copylen.wrapping_sub(6);
let nbits: usize = Log2FloorNonZero(tail as u64).wrapping_sub(1) as usize;
let prefix: usize = tail >> nbits;
let code: usize = (nbits << 1).wrapping_add(prefix).wrapping_add(44);
let extra: usize = tail.wrapping_sub(prefix << nbits);
(*commands)[0] = (code | extra << 8) as u32;
} else if copylen < 2118usize {
let tail: usize = copylen.wrapping_sub(70);
let nbits: usize = Log2FloorNonZero(tail as u64) as usize;
let code: usize = nbits.wrapping_add(52);
let extra: usize = tail.wrapping_sub(1usize << nbits);
(*commands)[0] = (code | extra << 8) as u32;
} else {
let extra: usize = copylen.wrapping_sub(2118);
(*commands)[0] = (63usize | extra << 8) as u32;
}
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
1
}
fn Hash(p: &[u8], shift: usize, length: usize) -> u32 {
let h: u64 =
(BROTLI_UNALIGNED_LOAD64(p) << ((8 - length) * 8)).wrapping_mul(kHashMul32 as (u64));
(h >> shift) as u32
}
fn IsMatch(p1: &[u8], p2: &[u8], length: usize) -> bool {
BROTLI_UNALIGNED_LOAD32(p1) == BROTLI_UNALIGNED_LOAD32(p2)
&& (length == 4 || (p1[4] == p2[4] && p1[5] == p2[5]))
}
#[allow(unused_assignments)]
fn CreateCommands(
input_index: usize,
block_size: usize,
input_size: usize,
base_ip: &[u8],
table: &mut [i32],
table_bits: usize,
min_match: usize,
literals: &mut &mut [u8],
num_literals: &mut usize,
commands: &mut &mut [u32],
num_commands: &mut usize,
) {
let mut ip_index: usize = input_index;
let shift: usize = (64u32 as usize).wrapping_sub(table_bits);
let ip_end: usize = input_index.wrapping_add(block_size);
let mut next_emit: usize = input_index;
let mut last_distance: i32 = -1i32;
let kInputMarginBytes: usize = 16usize;
if block_size >= kInputMarginBytes {
let len_limit: usize = min(
block_size.wrapping_sub(min_match),
input_size.wrapping_sub(kInputMarginBytes),
);
let ip_limit: usize = input_index.wrapping_add(len_limit);
let mut next_hash: u32;
let mut goto_emit_remainder = false;
next_hash = Hash(
&base_ip[{
ip_index = ip_index.wrapping_add(1);
ip_index
}..],
shift,
min_match,
);
while !goto_emit_remainder {
let mut skip: u32 = 32u32;
let mut next_ip: usize = ip_index;
let mut candidate: usize = 0;
loop {
{
'break3: loop {
{
let hash: u32 = next_hash;
let bytes_between_hash_lookups: u32 = skip >> 5;
skip = skip.wrapping_add(1);
ip_index = next_ip;
next_ip = ip_index.wrapping_add(bytes_between_hash_lookups as usize);
if next_ip > ip_limit {
goto_emit_remainder = true;
{
break 'break3;
}
}
next_hash = Hash(&base_ip[next_ip..], shift, min_match);
candidate = ip_index.wrapping_sub(last_distance as usize);
if IsMatch(&base_ip[ip_index..], &base_ip[candidate..], min_match)
&& candidate < ip_index
{
table[(hash as usize)] = ip_index.wrapping_sub(0) as i32;
{
break 'break3;
}
}
candidate = table[(hash as usize)] as usize;
table[(hash as usize)] = ip_index.wrapping_sub(0) as i32;
}
if IsMatch(&base_ip[ip_index..], &base_ip[candidate..], min_match) {
break;
}
}
}
if !(ip_index.wrapping_sub(candidate)
> (1usize << 18).wrapping_sub(16) as isize as usize
&& !goto_emit_remainder)
{
break;
}
}
if goto_emit_remainder {
break;
}
{
let base: usize = ip_index;
let matched: usize = min_match.wrapping_add(FindMatchLengthWithLimit(
&base_ip[(candidate + min_match)..],
&base_ip[(ip_index + min_match)..],
ip_end.wrapping_sub(ip_index).wrapping_sub(min_match),
));
let distance: i32 = base.wrapping_sub(candidate) as i32;
let insert: i32 = base.wrapping_sub(next_emit) as i32;
ip_index = ip_index.wrapping_add(matched);
*num_commands += EmitInsertLen(insert as u32, commands);
(*literals)[..(insert as usize)]
.clone_from_slice(&base_ip[next_emit..(next_emit + insert as usize)]);
*num_literals += insert as usize;
let new_literals = core::mem::take(literals);
let _ = core::mem::replace(literals, &mut new_literals[(insert as usize)..]);
if distance == last_distance {
(*commands)[0] = 64u32;
let remainder = core::mem::take(commands);
let _ = core::mem::replace(commands, &mut remainder[1..]);
*num_commands += 1;
} else {
*num_commands += EmitDistance(distance as u32, commands);
last_distance = distance;
}
*num_commands += EmitCopyLenLastDistance(matched, commands);
next_emit = ip_index;
if ip_index >= ip_limit {
goto_emit_remainder = true;
{
break;
}
}
{
let mut input_bytes: u64;
let mut prev_hash: u32;
let cur_hash: u32;
if min_match == 4 {
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 3)..]);
cur_hash = HashBytesAtOffset(input_bytes, 3i32, shift, min_match);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(3) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(2) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(1) as i32;
} else {
assert!(ip_index >= 5);
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 5)..]);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(5) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(4) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 2i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(3) as i32;
assert!(ip_index >= 2);
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 2)..]);
cur_hash = HashBytesAtOffset(input_bytes, 2i32, shift, min_match);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(2) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(1) as i32;
}
candidate = table[(cur_hash as usize)] as usize;
table[(cur_hash as usize)] = ip_index as i32;
}
}
while ip_index.wrapping_sub(candidate)
<= (1usize << 18).wrapping_sub(16) as isize as usize
&& IsMatch(&base_ip[ip_index..], &base_ip[candidate..], min_match)
{
let base_index: usize = ip_index;
let matched: usize = min_match.wrapping_add(FindMatchLengthWithLimit(
&base_ip[(candidate + min_match)..],
&base_ip[(ip_index + min_match)..],
ip_end.wrapping_sub(ip_index).wrapping_sub(min_match),
));
ip_index = ip_index.wrapping_add(matched);
last_distance = base_index.wrapping_sub(candidate) as i32;
*num_commands += EmitCopyLen(matched, commands);
*num_commands += EmitDistance(last_distance as u32, commands);
next_emit = ip_index;
if ip_index >= ip_limit {
goto_emit_remainder = true;
{
break;
}
}
{
assert!(ip_index >= 5);
let mut input_bytes: u64;
let cur_hash: u32;
let mut prev_hash: u32;
if min_match == 4 {
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 3)..]);
cur_hash = HashBytesAtOffset(input_bytes, 3i32, shift, min_match);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(3) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(2) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 2i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(1) as i32;
} else {
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 5)..]);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(5) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(4) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 2i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(3) as i32;
assert!(ip_index >= 2);
input_bytes = BROTLI_UNALIGNED_LOAD64(&base_ip[(ip_index - 2)..]);
cur_hash = HashBytesAtOffset(input_bytes, 2i32, shift, min_match);
prev_hash = HashBytesAtOffset(input_bytes, 0i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(2) as i32;
prev_hash = HashBytesAtOffset(input_bytes, 1i32, shift, min_match);
table[(prev_hash as usize)] = ip_index.wrapping_sub(1) as i32;
}
candidate = table[(cur_hash as usize)] as usize;
table[(cur_hash as usize)] = ip_index as i32;
}
}
if !goto_emit_remainder {
next_hash = Hash(
&base_ip[{
ip_index = ip_index.wrapping_add(1);
ip_index
}..],
shift,
min_match,
);
}
}
}
if next_emit < ip_end {
let insert: u32 = ip_end.wrapping_sub(next_emit) as u32;
*num_commands += EmitInsertLen(insert, commands);
literals[..insert as usize]
.clone_from_slice(&base_ip[next_emit..(next_emit + insert as usize)]);
let mut xliterals = core::mem::take(literals);
*literals = &mut core::mem::take(&mut xliterals)[(insert as usize)..];
*num_literals += insert as usize;
}
}
fn ShouldCompress(input: &[u8], input_size: usize, num_literals: usize) -> bool {
let corpus_size = input_size as floatX;
if (num_literals as floatX) < 0.98 * corpus_size {
true
} else {
let mut literal_histo: [u32; 256] = [0; 256];
let max_total_bit_cost: floatX = corpus_size * 8.0 * 0.98 / 43.0;
let mut i: usize;
i = 0usize;
while i < input_size {
{
let _rhs = 1;
let _lhs = &mut literal_histo[input[i] as usize];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
i = i.wrapping_add(43);
}
BitsEntropy(&mut literal_histo[..], 256) < max_total_bit_cost
}
}
pub fn BrotliWriteBits(n_bits: usize, bits: u64, pos: &mut usize, array: &mut [u8]) {
let p = &mut array[(*pos >> 3)..];
let mut v: u64 = p[0] as (u64);
v |= bits << (*pos & 7);
BROTLI_UNALIGNED_STORE64(p, v);
*pos = pos.wrapping_add(n_bits);
}
#[deprecated(note = "use store_meta_block_header instead")]
pub fn BrotliStoreMetaBlockHeader(
len: usize,
is_uncompressed: i32,
storage_ix: &mut usize,
storage: &mut [u8],
) {
store_meta_block_header(len, is_uncompressed != 0, storage_ix, storage);
}
pub(crate) fn store_meta_block_header(
len: usize,
is_uncompressed: bool,
storage_ix: &mut usize,
storage: &mut [u8],
) {
let mut nibbles: u64 = 6;
BrotliWriteBits(1, 0, storage_ix, storage);
if len <= (1u32 << 16) as usize {
nibbles = 4;
} else if len <= (1u32 << 20) as usize {
nibbles = 5;
}
BrotliWriteBits(2, nibbles.wrapping_sub(4), storage_ix, storage);
BrotliWriteBits(
nibbles.wrapping_mul(4) as usize,
len.wrapping_sub(1) as u64,
storage_ix,
storage,
);
BrotliWriteBits(1, u64::from(is_uncompressed), storage_ix, storage);
}
pub fn memcpy<T: Sized + Clone>(
dst: &mut [T],
dst_offset: usize,
src: &[T],
src_offset: usize,
size_to_copy: usize,
) {
dst[dst_offset..(dst_offset + size_to_copy)]
.clone_from_slice(&src[src_offset..(src_offset + size_to_copy)]);
}
fn BuildAndStoreCommandPrefixCode(
histogram: &[u32],
depth: &mut [u8],
bits: &mut [u16],
storage_ix: &mut usize,
storage: &mut [u8],
) {
let mut tree = [HuffmanTree::new(0, 0, 0); 129];
let mut cmd_depth: [u8; 704] = [0; 704];
let mut cmd_bits: [u16; 64] = [0; 64];
BrotliCreateHuffmanTree(histogram, 64usize, 15i32, &mut tree[..], depth);
BrotliCreateHuffmanTree(
&histogram[64..],
64usize,
14i32,
&mut tree[..],
&mut depth[64..],
);
memcpy(&mut cmd_depth[..], 0, depth, 24, 24);
memcpy(&mut cmd_depth[..], 24, depth, 0, 8);
memcpy(&mut cmd_depth[..], 32usize, depth, (48usize), 8usize);
memcpy(&mut cmd_depth[..], 40usize, depth, (8usize), 8usize);
memcpy(&mut cmd_depth[..], 48usize, depth, (56usize), 8usize);
memcpy(&mut cmd_depth[..], 56usize, depth, (16usize), 8usize);
BrotliConvertBitDepthsToSymbols(&mut cmd_depth[..], 64usize, &mut cmd_bits[..]);
memcpy(bits, 0, &cmd_bits[..], 24usize, 16usize);
memcpy(bits, (8usize), &cmd_bits[..], 40usize, 8usize);
memcpy(bits, (16usize), &cmd_bits[..], 56usize, 8usize);
memcpy(bits, (24usize), &cmd_bits[..], 0, 48usize);
memcpy(bits, (48usize), &cmd_bits[..], 32usize, 8usize);
memcpy(bits, (56usize), &cmd_bits[..], 48usize, 8usize);
BrotliConvertBitDepthsToSymbols(&mut depth[64..], 64usize, &mut bits[64..]);
{
for item in cmd_depth[..64].iter_mut() {
*item = 0;
}
memcpy(&mut cmd_depth[..], 0, depth, (24usize), 8usize);
memcpy(&mut cmd_depth[..], 64usize, depth, (32usize), 8usize);
memcpy(&mut cmd_depth[..], 128usize, depth, (40usize), 8usize);
memcpy(&mut cmd_depth[..], 192usize, depth, (48usize), 8usize);
memcpy(&mut cmd_depth[..], 384usize, depth, (56usize), 8usize);
for i in 0usize..8usize {
cmd_depth[(128usize).wrapping_add((8usize).wrapping_mul(i))] = depth[i];
cmd_depth[(256usize).wrapping_add((8usize).wrapping_mul(i))] = depth[i.wrapping_add(8)];
cmd_depth[(448usize).wrapping_add((8usize).wrapping_mul(i))] =
depth[i.wrapping_add(16)];
}
BrotliStoreHuffmanTree(
&mut cmd_depth[..],
704usize,
&mut tree[..],
storage_ix,
storage,
);
}
BrotliStoreHuffmanTree(
&mut depth[64..],
64usize,
&mut tree[..],
storage_ix,
storage,
);
}
fn StoreCommands<AllocHT: alloc::Allocator<HuffmanTree>>(
mht: &mut AllocHT,
mut literals: &[u8],
num_literals: usize,
commands: &[u32],
num_commands: usize,
storage_ix: &mut usize,
storage: &mut [u8],
) {
static kNumExtraBits: [u32; 128] = [
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6,
7, 8, 9, 10, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5,
5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17,
18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
];
static kInsertOffset: [u32; 24] = [
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114,
6210, 22594,
];
let mut lit_depths: [u8; 256] = [0; 256];
let mut lit_bits: [u16; 256] = [0; 256]; let mut lit_histo: [u32; 256] = [0; 256]; let mut cmd_depths: [u8; 128] = [0; 128];
let mut cmd_bits: [u16; 128] = [0; 128];
let mut cmd_histo: [u32; 128] = [0; 128];
let mut i: usize;
for i in 0usize..num_literals {
let _rhs = 1;
let _lhs = &mut lit_histo[literals[i] as usize];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
BrotliBuildAndStoreHuffmanTreeFast(
mht,
&lit_histo[..],
num_literals,
8usize,
&mut lit_depths[..],
&mut lit_bits[..],
storage_ix,
storage,
);
i = 0usize;
while i < num_commands {
{
let code: u32 = commands[i] & 0xffu32;
{
let _rhs = 1;
let _lhs = &mut cmd_histo[code as usize];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
}
i = i.wrapping_add(1);
}
{
let _rhs = 1i32;
let _lhs = &mut cmd_histo[1];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
{
let _rhs = 1i32;
let _lhs = &mut cmd_histo[2];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
{
let _rhs = 1i32;
let _lhs = &mut cmd_histo[64];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
{
let _rhs = 1i32;
let _lhs = &mut cmd_histo[84];
*_lhs = (*_lhs).wrapping_add(_rhs as u32);
}
BuildAndStoreCommandPrefixCode(
&mut cmd_histo[..],
&mut cmd_depths[..],
&mut cmd_bits[..],
storage_ix,
storage,
);
for i in 0usize..num_commands {
let cmd: u32 = commands[i];
let code: u32 = cmd & 0xffu32;
let extra: u32 = cmd >> 8;
BrotliWriteBits(
cmd_depths[code as usize] as usize,
cmd_bits[code as usize] as (u64),
storage_ix,
storage,
);
BrotliWriteBits(
kNumExtraBits[code as usize] as usize,
extra as (u64),
storage_ix,
storage,
);
if code < 24u32 {
let insert: u32 = kInsertOffset[code as usize].wrapping_add(extra);
for literal in literals[..(insert as usize)].iter() {
let lit: u8 = *literal;
BrotliWriteBits(
lit_depths[lit as usize] as usize,
lit_bits[lit as usize] as (u64),
storage_ix,
storage,
);
}
literals = &literals[insert as usize..];
}
}
}
fn EmitUncompressedMetaBlock(
input: &[u8],
input_size: usize,
storage_ix: &mut usize,
storage: &mut [u8],
) {
store_meta_block_header(input_size, true, storage_ix, storage);
*storage_ix = storage_ix.wrapping_add(7u32 as usize) & !7u32 as usize;
memcpy(storage, (*storage_ix >> 3), input, 0, input_size);
*storage_ix = storage_ix.wrapping_add(input_size << 3);
storage[(*storage_ix >> 3)] = 0u8;
}
#[allow(unused_variables)]
#[inline(always)]
fn compress_fragment_two_pass_impl<AllocHT: alloc::Allocator<HuffmanTree>>(
m: &mut AllocHT,
base_ip: &[u8],
mut input_size: usize,
is_last: bool,
command_buf: &mut [u32],
literal_buf: &mut [u8],
table: &mut [i32],
table_bits: usize,
min_match: usize,
storage_ix: &mut usize,
storage: &mut [u8],
) {
let mut input_index: usize = 0usize;
while input_size > 0usize {
let block_size: usize = min(input_size, kCompressFragmentTwoPassBlockSize);
let mut num_literals: usize = 0;
let mut num_commands: usize = 0;
{
let mut literals = &mut literal_buf[..];
let mut commands = &mut command_buf[..];
CreateCommands(
input_index,
block_size,
input_size,
base_ip,
table,
table_bits,
min_match,
&mut literals,
&mut num_literals,
&mut commands,
&mut num_commands,
);
}
if ShouldCompress(&base_ip[input_index..], block_size, num_literals) {
store_meta_block_header(block_size, false, storage_ix, storage);
BrotliWriteBits(13usize, 0, storage_ix, storage);
StoreCommands(
m,
literal_buf,
num_literals,
command_buf,
num_commands,
storage_ix,
storage,
);
} else {
EmitUncompressedMetaBlock(&base_ip[input_index..], block_size, storage_ix, storage);
}
input_index = input_index.wrapping_add(block_size);
input_size = input_size.wrapping_sub(block_size);
}
}
macro_rules! compress_specialization {
($table_bits : expr, $fname: ident) => {
fn $fname<AllocHT: alloc::Allocator<HuffmanTree>>(
mht: &mut AllocHT,
input: &[u8],
input_size: usize,
is_last: bool,
command_buf: &mut [u32],
literal_buf: &mut [u8],
table: &mut [i32],
storage_ix: &mut usize,
storage: &mut [u8],
) {
let min_match = if $table_bits < 15 { 4 } else { 6 };
compress_fragment_two_pass_impl(
mht,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
$table_bits,
min_match,
storage_ix,
storage,
);
}
};
}
compress_specialization!(8, BrotliCompressFragmentTwoPassImpl8);
compress_specialization!(9, BrotliCompressFragmentTwoPassImpl9);
compress_specialization!(10, BrotliCompressFragmentTwoPassImpl10);
compress_specialization!(11, BrotliCompressFragmentTwoPassImpl11);
compress_specialization!(12, BrotliCompressFragmentTwoPassImpl12);
compress_specialization!(13, BrotliCompressFragmentTwoPassImpl13);
compress_specialization!(14, BrotliCompressFragmentTwoPassImpl14);
compress_specialization!(15, BrotliCompressFragmentTwoPassImpl15);
compress_specialization!(16, BrotliCompressFragmentTwoPassImpl16);
compress_specialization!(17, BrotliCompressFragmentTwoPassImpl17);
fn RewindBitPosition(new_storage_ix: usize, storage_ix: &mut usize, storage: &mut [u8]) {
let bitpos: usize = new_storage_ix & 7usize;
let mask: usize = (1u32 << bitpos).wrapping_sub(1) as usize;
{
let _rhs = mask as u8;
let _lhs = &mut storage[(new_storage_ix >> 3)];
*_lhs = (*_lhs as i32 & _rhs as i32) as u8;
}
*storage_ix = new_storage_ix;
}
#[deprecated(note = "use compress_fragment_two_pass instead")]
pub fn BrotliCompressFragmentTwoPass<AllocHT: alloc::Allocator<HuffmanTree>>(
m: &mut AllocHT,
input: &[u8],
input_size: usize,
is_last: i32,
command_buf: &mut [u32],
literal_buf: &mut [u8],
table: &mut [i32],
table_size: usize,
storage_ix: &mut usize,
storage: &mut [u8],
) {
compress_fragment_two_pass(
m,
input,
input_size,
is_last != 0,
command_buf,
literal_buf,
table,
table_size,
storage_ix,
storage,
)
}
pub(crate) fn compress_fragment_two_pass<AllocHT: alloc::Allocator<HuffmanTree>>(
m: &mut AllocHT,
input: &[u8],
input_size: usize,
is_last: bool,
command_buf: &mut [u32],
literal_buf: &mut [u8],
table: &mut [i32],
table_size: usize,
storage_ix: &mut usize,
storage: &mut [u8],
) {
let initial_storage_ix: usize = *storage_ix;
let table_bits: usize = Log2FloorNonZero(table_size as u64) as usize;
if table_bits == 8usize {
BrotliCompressFragmentTwoPassImpl8(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 9usize {
BrotliCompressFragmentTwoPassImpl9(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 10usize {
BrotliCompressFragmentTwoPassImpl10(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 11usize {
BrotliCompressFragmentTwoPassImpl11(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 12usize {
BrotliCompressFragmentTwoPassImpl12(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 13usize {
BrotliCompressFragmentTwoPassImpl13(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 14usize {
BrotliCompressFragmentTwoPassImpl14(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 15usize {
BrotliCompressFragmentTwoPassImpl15(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 16usize {
BrotliCompressFragmentTwoPassImpl16(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if table_bits == 17usize {
BrotliCompressFragmentTwoPassImpl17(
m,
input,
input_size,
is_last,
command_buf,
literal_buf,
table,
storage_ix,
storage,
);
}
if storage_ix.wrapping_sub(initial_storage_ix) > (31usize).wrapping_add(input_size << 3) {
RewindBitPosition(initial_storage_ix, storage_ix, storage);
EmitUncompressedMetaBlock(input, input_size, storage_ix, storage);
}
if is_last {
BrotliWriteBits(1, 1, storage_ix, storage);
BrotliWriteBits(1, 1, storage_ix, storage);
*storage_ix = storage_ix.wrapping_add(7u32 as usize) & !7u32 as usize;
}
}