Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

305
vendor/fdeflate/src/compress.rs vendored Normal file
View File

@@ -0,0 +1,305 @@
use simd_adler32::Adler32;
use std::io::{self, Seek, SeekFrom, Write};
use crate::tables::{
BITMASKS, HUFFMAN_CODES, HUFFMAN_LENGTHS, LENGTH_TO_LEN_EXTRA, LENGTH_TO_SYMBOL,
};
/// Compressor that produces fdeflate compressed streams.
pub struct Compressor<W: Write> {
checksum: Adler32,
buffer: u64,
nbits: u8,
writer: W,
}
impl<W: Write> Compressor<W> {
fn write_bits(&mut self, bits: u64, nbits: u8) -> io::Result<()> {
debug_assert!(nbits <= 64);
self.buffer |= bits << self.nbits;
self.nbits += nbits;
if self.nbits >= 64 {
self.writer.write_all(&self.buffer.to_le_bytes())?;
self.nbits -= 64;
self.buffer = bits.checked_shr((nbits - self.nbits) as u32).unwrap_or(0);
}
debug_assert!(self.nbits < 64);
Ok(())
}
fn flush(&mut self) -> io::Result<()> {
if self.nbits % 8 != 0 {
self.write_bits(0, 8 - self.nbits % 8)?;
}
if self.nbits > 0 {
self.writer
.write_all(&self.buffer.to_le_bytes()[..self.nbits as usize / 8])
.unwrap();
self.buffer = 0;
self.nbits = 0;
}
Ok(())
}
fn write_run(&mut self, mut run: u32) -> io::Result<()> {
self.write_bits(HUFFMAN_CODES[0] as u64, HUFFMAN_LENGTHS[0])?;
run -= 1;
while run >= 258 {
self.write_bits(HUFFMAN_CODES[285] as u64, HUFFMAN_LENGTHS[285] + 1)?;
run -= 258;
}
if run > 4 {
let sym = LENGTH_TO_SYMBOL[run as usize - 3] as usize;
self.write_bits(HUFFMAN_CODES[sym] as u64, HUFFMAN_LENGTHS[sym])?;
let len_extra = LENGTH_TO_LEN_EXTRA[run as usize - 3];
let extra = ((run - 3) & BITMASKS[len_extra as usize]) as u64;
self.write_bits(extra, len_extra + 1)?;
} else {
debug_assert_eq!(HUFFMAN_CODES[0], 0);
self.write_bits(0, run as u8 * HUFFMAN_LENGTHS[0])?;
}
Ok(())
}
/// Create a new Compressor.
pub fn new(writer: W) -> io::Result<Self> {
let mut compressor = Self {
checksum: Adler32::new(),
buffer: 0,
nbits: 0,
writer,
};
compressor.write_headers()?;
Ok(compressor)
}
fn write_headers(&mut self) -> io::Result<()> {
const HEADER: [u8; 54] = [
120, 1, 237, 192, 3, 160, 36, 89, 150, 198, 241, 255, 119, 238, 141, 200, 204, 167,
114, 75, 99, 174, 109, 219, 182, 109, 219, 182, 109, 219, 182, 109, 105, 140, 158, 150,
74, 175, 158, 50, 51, 34, 238, 249, 118, 183, 106, 122, 166, 135, 59, 107, 213, 15,
];
self.writer.write_all(&HEADER[..53]).unwrap();
self.write_bits(HEADER[53] as u64, 5)?;
Ok(())
}
/// Write data to the compressor.
pub fn write_data(&mut self, data: &[u8]) -> io::Result<()> {
self.checksum.write(data);
let mut run = 0;
let mut chunks = data.chunks_exact(8);
for chunk in &mut chunks {
let ichunk = u64::from_le_bytes(chunk.try_into().unwrap());
if ichunk == 0 {
run += 8;
continue;
} else if run > 0 {
let run_extra = ichunk.trailing_zeros() / 8;
self.write_run(run + run_extra)?;
run = 0;
if run_extra > 0 {
run = ichunk.leading_zeros() / 8;
for &b in &chunk[run_extra as usize..8 - run as usize] {
self.write_bits(
HUFFMAN_CODES[b as usize] as u64,
HUFFMAN_LENGTHS[b as usize],
)?;
}
continue;
}
}
let run_start = ichunk.leading_zeros() / 8;
if run_start > 0 {
for &b in &chunk[..8 - run_start as usize] {
self.write_bits(
HUFFMAN_CODES[b as usize] as u64,
HUFFMAN_LENGTHS[b as usize],
)?;
}
run = run_start;
continue;
}
let n0 = HUFFMAN_LENGTHS[chunk[0] as usize];
let n1 = HUFFMAN_LENGTHS[chunk[1] as usize];
let n2 = HUFFMAN_LENGTHS[chunk[2] as usize];
let n3 = HUFFMAN_LENGTHS[chunk[3] as usize];
let bits = HUFFMAN_CODES[chunk[0] as usize] as u64
| ((HUFFMAN_CODES[chunk[1] as usize] as u64) << n0)
| ((HUFFMAN_CODES[chunk[2] as usize] as u64) << (n0 + n1))
| ((HUFFMAN_CODES[chunk[3] as usize] as u64) << (n0 + n1 + n2));
self.write_bits(bits, n0 + n1 + n2 + n3)?;
let n4 = HUFFMAN_LENGTHS[chunk[4] as usize];
let n5 = HUFFMAN_LENGTHS[chunk[5] as usize];
let n6 = HUFFMAN_LENGTHS[chunk[6] as usize];
let n7 = HUFFMAN_LENGTHS[chunk[7] as usize];
let bits2 = HUFFMAN_CODES[chunk[4] as usize] as u64
| ((HUFFMAN_CODES[chunk[5] as usize] as u64) << n4)
| ((HUFFMAN_CODES[chunk[6] as usize] as u64) << (n4 + n5))
| ((HUFFMAN_CODES[chunk[7] as usize] as u64) << (n4 + n5 + n6));
self.write_bits(bits2, n4 + n5 + n6 + n7)?;
}
if run > 0 {
self.write_run(run)?;
}
for &b in chunks.remainder() {
self.write_bits(
HUFFMAN_CODES[b as usize] as u64,
HUFFMAN_LENGTHS[b as usize],
)?;
}
Ok(())
}
/// Write the remainder of the stream and return the inner writer.
pub fn finish(mut self) -> io::Result<W> {
// Write end of block
self.write_bits(HUFFMAN_CODES[256] as u64, HUFFMAN_LENGTHS[256])?;
self.flush()?;
// Write Adler32 checksum
let checksum: u32 = self.checksum.finish();
self.writer
.write_all(checksum.to_be_bytes().as_ref())
.unwrap();
Ok(self.writer)
}
}
/// Compressor that only writes the stored blocks.
///
/// This is useful for writing files that are not compressed, but still need to be wrapped in a
/// zlib stream.
pub struct StoredOnlyCompressor<W> {
writer: W,
checksum: Adler32,
block_bytes: u16,
}
impl<W: Write + Seek> StoredOnlyCompressor<W> {
/// Creates a new `StoredOnlyCompressor` that writes to the given writer.
pub fn new(mut writer: W) -> io::Result<Self> {
writer.write_all(&[0x78, 0x01])?; // zlib header
writer.write_all(&[0; 5])?; // placeholder stored block header
Ok(Self {
writer,
checksum: Adler32::new(),
block_bytes: 0,
})
}
fn set_block_header(&mut self, size: u16, last: bool) -> io::Result<()> {
self.writer.seek(SeekFrom::Current(-(size as i64 + 5)))?;
self.writer.write_all(&[
last as u8,
(size & 0xFF) as u8,
((size >> 8) & 0xFF) as u8,
(!size & 0xFF) as u8,
((!size >> 8) & 0xFF) as u8,
])?;
self.writer.seek(SeekFrom::Current(size as i64))?;
Ok(())
}
/// Writes the given data to the underlying writer.
pub fn write_data(&mut self, mut data: &[u8]) -> io::Result<()> {
self.checksum.write(data);
while !data.is_empty() {
if self.block_bytes == u16::MAX {
self.set_block_header(u16::MAX, false)?;
self.writer.write_all(&[0; 5])?; // placeholder stored block header
self.block_bytes = 0;
}
let prefix_bytes = data.len().min((u16::MAX - self.block_bytes) as usize);
self.writer.write_all(&data[..prefix_bytes])?;
self.block_bytes += prefix_bytes as u16;
data = &data[prefix_bytes..];
}
Ok(())
}
/// Finish writing the final block and return the underlying writer.
pub fn finish(mut self) -> io::Result<W> {
self.set_block_header(self.block_bytes, true)?;
// Write Adler32 checksum
let checksum: u32 = self.checksum.finish();
self.writer
.write_all(checksum.to_be_bytes().as_ref())
.unwrap();
Ok(self.writer)
}
}
impl<W> StoredOnlyCompressor<W> {
/// Return the number of bytes that will be written to the output stream
/// for the given input size. Because this compressor only writes stored blocks,
/// the output size is always slightly *larger* than the input size.
pub fn compressed_size(raw_size: usize) -> usize {
(raw_size.saturating_sub(1) / u16::MAX as usize) * (u16::MAX as usize + 5)
+ (raw_size % u16::MAX as usize + 5)
+ 6
}
}
/// Compresses the given data.
pub fn compress_to_vec(input: &[u8]) -> Vec<u8> {
let mut compressor = Compressor::new(Vec::with_capacity(input.len() / 4)).unwrap();
compressor.write_data(input).unwrap();
compressor.finish().unwrap()
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
fn roundtrip(data: &[u8]) {
let compressed = compress_to_vec(data);
let decompressed = miniz_oxide::inflate::decompress_to_vec_zlib(&compressed).unwrap();
assert_eq!(&decompressed, data);
}
#[test]
fn it_works() {
roundtrip(b"Hello world!");
}
#[test]
fn constant() {
roundtrip(&vec![0; 2048]);
roundtrip(&vec![5; 2048]);
roundtrip(&vec![128; 2048]);
roundtrip(&vec![254; 2048]);
}
#[test]
fn random() {
let mut rng = rand::thread_rng();
let mut data = vec![0; 2048];
for _ in 0..10 {
for byte in &mut data {
*byte = rng.gen();
}
roundtrip(&data);
}
}
}

1343
vendor/fdeflate/src/decompress.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,101 @@
//! Testing utilities for testing `fdeflate::Decompressor`.
//!
//! These utilities are used by:
//!
//! * Unit tests (e.g. `#[test]` tests in `src/decompress.rs`)
//! * Fuzzers (e.g. `fuzz/fuzz_targets/inflate_bytewise3.rs`)
#[cfg(test)]
use crate as fdeflate;
use fdeflate::{DecompressionError, Decompressor};
#[derive(Debug, PartialEq)]
pub enum TestDecompressionError {
ProdError(DecompressionError),
TestError(TestErrorKind),
}
#[derive(Debug, Eq, PartialEq)]
pub enum TestErrorKind {
OutputTooLarge,
TooManyIterations,
}
impl From<DecompressionError> for TestDecompressionError {
fn from(e: DecompressionError) -> Self {
Self::ProdError(e)
}
}
impl From<TestErrorKind> for TestDecompressionError {
fn from(kind: TestErrorKind) -> Self {
Self::TestError(kind)
}
}
/// Decompresses `input` when feeding it into a `Decompressor::read` in `chunks`.
///
/// `chunks` typically can be used to decode the whole input at once (setting `chunks` to
/// `vec![input.len]`) or byte-by-byte (setting `chunks` to `std::iter::repeat(1)`).
/// But `chunks` can also be used to replicate arbitrary chunking patterns (such as may be
/// used by some fuzzing-based repros from the `png` crate).
///
/// `early_eof` is used to the last `end_of_input` argument of `Decompressor::read` calls.
/// When `early_eof` is `false`, then `end_of_input` is `false` until the whole input is
/// consumed (and then is `Decompressor::is_done` is still false, then `Decompressor::read`
/// is called one or more times with empty input slice and `end_of_input` set to true).
/// When `early_eof` is `true` then `end_of_input` is set to `true` as soon as the slice
/// fed to `Decompressor::read` "reaches" the end of the whole input.
///
/// Unlike the `png` crate, this testing helper uses a big, fixed-size output buffer.
/// (i.e. there is no simulation of `ZlibStream.compact_out_buffer_if_needed` from the `png`
/// crate).
pub fn decompress_by_chunks(
input: &[u8],
chunks: impl IntoIterator<Item = usize>,
early_eof: bool,
) -> Result<Vec<u8>, TestDecompressionError> {
let mut chunks = chunks.into_iter();
// `iteration_counter` helps to prevent infinite loops (which may happen with `chunks` such
// as `std::iter::repeat(0)`).
let mut iteration_counter = 0;
// Ignoring checksums so that we can work with inputs generated by fuzzing. (Fuzzing
// typically ignores checksums to make it easier to explore the space of possible inputs.)
let mut d = Decompressor::new();
d.ignore_adler32();
let mut out_buf = vec![0; 1_000_000];
let mut in_pos = 0;
let mut out_pos = 0;
while !d.is_done() {
iteration_counter += 1;
if iteration_counter > 5000 {
return Err(TestErrorKind::TooManyIterations.into());
}
let chunk_size = chunks.next().unwrap_or(0);
let start = in_pos;
let end = std::cmp::min(start + chunk_size, input.len());
let eof = if early_eof {
end == input.len()
} else {
start == input.len()
};
let (in_consumed, out_written) =
d.read(&input[start..end], out_buf.as_mut_slice(), out_pos, eof)?;
in_pos += in_consumed;
out_pos += out_written;
if out_pos == out_buf.len() && in_consumed == 0 && !d.is_done() {
return Err(TestErrorKind::OutputTooLarge.into());
}
}
out_buf.resize(out_pos, 0xFF);
Ok(out_buf)
}

182
vendor/fdeflate/src/huffman.rs vendored Normal file
View File

@@ -0,0 +1,182 @@
use crate::decompress::{EXCEPTIONAL_ENTRY, LITERAL_ENTRY, SECONDARY_TABLE_ENTRY};
/// Return the next code, or if the codeword is already all ones (which is the final code), return
/// the same code again.
fn next_codeword(mut codeword: u16, table_size: u16) -> u16 {
if codeword == table_size - 1 {
return codeword;
}
let adv = (u16::BITS - 1) - (codeword ^ (table_size - 1)).leading_zeros();
let bit = 1 << adv;
codeword &= bit - 1;
codeword |= bit;
codeword
}
#[allow(clippy::needless_range_loop)]
pub fn build_table(
lengths: &[u8],
entries: &[u32],
codes: &mut [u16],
primary_table: &mut [u32],
secondary_table: &mut Vec<u16>,
is_distance_table: bool,
double_literal: bool,
) -> bool {
// Count the number of symbols with each code length.
let mut histogram = [0; 16];
for &length in lengths {
histogram[length as usize] += 1;
}
// Determine the maximum code length.
let mut max_length = 15;
while max_length > 1 && histogram[max_length] == 0 {
max_length -= 1;
}
// Handle zero and one symbol huffman codes (which are only allowed for distance codes).
if is_distance_table {
if max_length == 0 {
primary_table.fill(0);
secondary_table.clear();
return true;
} else if max_length == 1 && histogram[1] == 1 {
let symbol = lengths.iter().position(|&l| l == 1).unwrap();
codes[symbol] = 0;
let entry = entries
.get(symbol)
.cloned()
.unwrap_or((symbol as u32) << 16)
| 1;
for chunk in primary_table.chunks_mut(2) {
chunk[0] = entry;
chunk[1] = 0;
}
return true;
}
}
// Sort symbols by code length. Given the histogram, we can determine the starting offset
// for each code length.
let mut offsets = [0; 16];
let mut codespace_used = 0;
offsets[1] = histogram[0];
for i in 1..max_length {
offsets[i + 1] = offsets[i] + histogram[i];
codespace_used = (codespace_used << 1) + histogram[i];
}
codespace_used = (codespace_used << 1) + histogram[max_length];
// Check that the provided lengths form a valid Huffman tree.
if codespace_used != (1 << max_length) {
return false;
}
// Sort the symbols by code length.
let mut next_index = offsets;
let mut sorted_symbols = [0; 288];
for symbol in 0..lengths.len() {
let length = lengths[symbol];
sorted_symbols[next_index[length as usize]] = symbol;
next_index[length as usize] += 1;
}
let mut codeword = 0u16;
let mut i = histogram[0];
// Populate the primary decoding table
let primary_table_bits = primary_table.len().ilog2() as usize;
let primary_table_mask = (1 << primary_table_bits) - 1;
for length in 1..=primary_table_bits {
let current_table_end = 1 << length;
// Loop over all symbols with the current code length and set their table entries.
for _ in 0..histogram[length] {
let symbol = sorted_symbols[i];
i += 1;
primary_table[codeword as usize] = entries
.get(symbol)
.cloned()
.unwrap_or((symbol as u32) << 16)
| length as u32;
codes[symbol] = codeword;
codeword = next_codeword(codeword, current_table_end as u16);
}
if double_literal {
for len1 in 1..(length - 1) {
let len2 = length - len1;
for sym1_index in offsets[len1]..next_index[len1] {
for sym2_index in offsets[len2]..next_index[len2] {
let sym1 = sorted_symbols[sym1_index];
let sym2 = sorted_symbols[sym2_index];
if sym1 < 256 && sym2 < 256 {
let codeword1 = codes[sym1];
let codeword2 = codes[sym2];
let codeword = codeword1 | (codeword2 << len1);
let entry = (sym1 as u32) << 16
| (sym2 as u32) << 24
| LITERAL_ENTRY
| (2 << 8);
primary_table[codeword as usize] = entry | (length as u32);
}
}
}
}
}
// If we aren't at the maximum table size, double the size of the table.
if length < primary_table_bits {
primary_table.copy_within(0..current_table_end, current_table_end);
}
}
// Populate the secondary decoding table.
secondary_table.clear();
if max_length > primary_table_bits {
let mut subtable_start = 0;
let mut subtable_prefix = !0;
for length in (primary_table_bits + 1)..=max_length {
let subtable_size = 1 << (length - primary_table_bits);
for _ in 0..histogram[length] {
// If the codeword's prefix doesn't match the current subtable, create a new
// subtable.
if codeword & primary_table_mask != subtable_prefix {
subtable_prefix = codeword & primary_table_mask;
subtable_start = secondary_table.len();
primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16)
| EXCEPTIONAL_ENTRY
| SECONDARY_TABLE_ENTRY
| (subtable_size as u32 - 1);
secondary_table.resize(subtable_start + subtable_size, 0);
}
// Lookup the symbol.
let symbol = sorted_symbols[i];
i += 1;
// Insert the symbol into the secondary table and advance to the next codeword.
codes[symbol] = codeword;
secondary_table[subtable_start + (codeword >> primary_table_bits) as usize] =
((symbol as u16) << 4) | (length as u16);
codeword = next_codeword(codeword, 1 << length);
}
// If there are more codes with the same subtable prefix, extend the subtable.
if length < max_length && codeword & primary_table_mask == subtable_prefix {
secondary_table.extend_from_within(subtable_start..);
let subtable_size = secondary_table.len() - subtable_start;
primary_table[subtable_prefix as usize] = ((subtable_start as u32) << 16)
| EXCEPTIONAL_ENTRY
| SECONDARY_TABLE_ENTRY
| (subtable_size as u32 - 1);
}
}
}
true
}

124
vendor/fdeflate/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,124 @@
//! A fast deflate implementation.
//!
//! This crate contains an optimized implementation of the deflate algorithm tuned to compress PNG
//! images. It is compatible with standard zlib, but make a bunch of simplifying assumptions that
//! drastically improve encoding performance:
//!
//! - Exactly one block per deflate stream.
//! - No distance codes except for run length encoding of zeros.
//! - A single fixed huffman tree trained on a large corpus of PNG images.
//! - All huffman codes are 12 bits or less.
//!
//! It also contains a fast decompressor that supports arbitrary zlib streams but does especially
//! well on streams that meet the above assumptions.
//!
//! # Inspiration
//!
//! The algorithms in this crate take inspiration from multiple sources:
//! * [fpnge](https://github.com/veluca93/fpnge)
//! * [zune-inflate](https://github.com/etemesi254/zune-image/tree/main/zune-inflate)
//! * [RealTime Data Compression blog](https://fastcompression.blogspot.com/2015/10/huffman-revisited-part-4-multi-bytes.html)
#![forbid(unsafe_code)]
#![warn(missing_docs)]
mod compress;
mod decompress;
mod huffman;
mod tables;
pub use compress::{compress_to_vec, Compressor, StoredOnlyCompressor};
pub use decompress::{
decompress_to_vec, decompress_to_vec_bounded, BoundedDecompressionError, DecompressionError,
Decompressor,
};
/// Build a length limited huffman tree.
///
/// Dynamic programming algorithm from fpnge.
#[doc(hidden)]
pub fn compute_code_lengths(
freqs: &[u64],
min_limit: &[u8],
max_limit: &[u8],
calculated_nbits: &mut [u8],
) {
debug_assert_eq!(freqs.len(), min_limit.len());
debug_assert_eq!(freqs.len(), max_limit.len());
debug_assert_eq!(freqs.len(), calculated_nbits.len());
let len = freqs.len();
for i in 0..len {
debug_assert!(min_limit[i] >= 1);
debug_assert!(min_limit[i] <= max_limit[i]);
}
let precision = *max_limit.iter().max().unwrap();
let num_patterns = 1 << precision;
let mut dynp = vec![u64::MAX; (num_patterns + 1) * (len + 1)];
let index = |sym: usize, off: usize| sym * (num_patterns + 1) + off;
dynp[index(0, 0)] = 0;
for sym in 0..len {
for bits in min_limit[sym]..=max_limit[sym] {
let off_delta = 1 << (precision - bits);
for off in 0..=num_patterns.saturating_sub(off_delta) {
dynp[index(sym + 1, off + off_delta)] = dynp[index(sym, off)]
.saturating_add(freqs[sym] * u64::from(bits))
.min(dynp[index(sym + 1, off + off_delta)]);
}
}
}
let mut sym = len;
let mut off = num_patterns;
while sym > 0 {
sym -= 1;
assert!(off > 0);
for bits in min_limit[sym]..=max_limit[sym] {
let off_delta = 1 << (precision - bits);
if off_delta <= off
&& dynp[index(sym + 1, off)]
== dynp[index(sym, off - off_delta)]
.saturating_add(freqs[sym] * u64::from(bits))
{
off -= off_delta;
calculated_nbits[sym] = bits;
break;
}
}
}
for i in 0..len {
debug_assert!(calculated_nbits[i] >= min_limit[i]);
debug_assert!(calculated_nbits[i] <= max_limit[i]);
}
}
const fn compute_codes<const NSYMS: usize>(lengths: &[u8; NSYMS]) -> Option<[u16; NSYMS]> {
let mut codes = [0u16; NSYMS];
let mut code = 0u32;
let mut len = 1;
while len <= 16 {
let mut i = 0;
while i < lengths.len() {
if lengths[i] == len {
codes[i] = (code as u16).reverse_bits() >> (16 - len);
code += 1;
}
i += 1;
}
code <<= 1;
len += 1;
}
if code == 2 << 16 {
Some(codes)
} else {
None
}
}

221
vendor/fdeflate/src/tables.rs vendored Normal file
View File

@@ -0,0 +1,221 @@
use crate::decompress::{EXCEPTIONAL_ENTRY, LITERAL_ENTRY};
/// Hard-coded Huffman codes used regardless of the input.
///
/// These values work well for PNGs with some form of filtering enabled, but will likely make most
/// other inputs worse.
pub(crate) const HUFFMAN_LENGTHS: [u8; 286] = [
2, 3, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10,
10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 10, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, 9, 8, 8, 8, 8, 8, 7,
7, 7, 6, 6, 6, 5, 4, 3, 12, 12, 12, 9, 9, 11, 10, 11, 11, 10, 11, 11, 11, 11, 11, 11, 12, 11,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9,
];
pub(crate) const HUFFMAN_CODES: [u16; 286] = match crate::compute_codes(&HUFFMAN_LENGTHS) {
Some(codes) => codes,
None => panic!("HUFFMAN_LENGTHS is invalid"),
};
/// Length code for length values (derived from deflate spec).
pub(crate) const LENGTH_TO_SYMBOL: [u16; 256] = [
257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269,
269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273,
273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276,
276, 276, 276, 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280,
280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
282, 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
284, 284, 284, 284, 284, 284, 284, 284, 285,
];
/// Number of extra bits for length values (derived from deflate spec).
pub(crate) const LENGTH_TO_LEN_EXTRA: [u8; 256] = [
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0,
];
pub(crate) const BITMASKS: [u32; 17] = [
0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
];
/// Order of the length code length alphabet (derived from deflate spec).
pub(crate) const CLCL_ORDER: [usize; 19] = [
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
];
/// Number of extra bits for each length code (derived from deflate spec).
pub(crate) const LEN_SYM_TO_LEN_EXTRA: [u8; 29] = [
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
];
/// The base length for each length code (derived from deflate spec).
pub(crate) const LEN_SYM_TO_LEN_BASE: [usize; 29] = [
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131,
163, 195, 227, 258,
];
/// Number of extra bits for each distance code (derived from deflate spec.)
pub(crate) const DIST_SYM_TO_DIST_EXTRA: [u8; 30] = [
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,
];
/// The base distance for each distance code (derived from deflate spec).
pub(crate) const DIST_SYM_TO_DIST_BASE: [u16; 30] = [
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577,
];
/// The main litlen_table uses a 12-bit input to lookup the meaning of the symbol. The table is
/// split into 4 sections:
///
/// aaaaaaaa_bbbbbbbb_1000yyyy_0000xxxx x = input_advance_bits, y = output_advance_bytes (literal)
/// 0000000z_zzzzzzzz_00000yyy_0000xxxx x = input_advance_bits, y = extra_bits, z = distance_base (length)
/// 00000000_00000000_01000000_0000xxxx x = input_advance_bits (EOF)
/// 0000xxxx_xxxxxxxx_01100000_00000000 x = secondary_table_index
/// 00000000_00000000_01000000_00000000 invalid code
pub(crate) const LITLEN_TABLE_ENTRIES: [u32; 288] = {
let mut entries = [EXCEPTIONAL_ENTRY; 288];
let mut i = 0;
while i < 256 {
entries[i] = (i as u32) << 16 | LITERAL_ENTRY | (1 << 8);
i += 1;
}
let mut i = 257;
while i < 286 {
entries[i] = (LEN_SYM_TO_LEN_BASE[i - 257] as u32) << 16
| (LEN_SYM_TO_LEN_EXTRA[i - 257] as u32) << 8;
i += 1;
}
entries
};
/// The distance table is a 512-entry table that maps 9 bits of distance symbols to their meaning.
///
/// 00000000_00000000_00000000_00000000 symbol is more than 9 bits
/// zzzzzzzz_zzzzzzzz_0000yyyy_0000xxxx x = input_advance_bits, y = extra_bits, z = distance_base
pub(crate) const DISTANCE_TABLE_ENTRIES: [u32; 32] = {
let mut entries = [0; 32];
let mut i = 0;
while i < 30 {
entries[i] = (DIST_SYM_TO_DIST_BASE[i] as u32) << 16
| (DIST_SYM_TO_DIST_EXTRA[i] as u32) << 8
| LITERAL_ENTRY;
i += 1;
}
entries
};
pub(crate) const FIXED_LITLEN_TABLE: [u32; 512] = [
16391, 5275912, 1081608, 7537672, 2032135, 7373064, 3178760, 12615945, 655367, 6324488,
2130184, 10518793, 33032, 8421640, 4227336, 14713097, 393223, 5800200, 1605896, 9470217,
3867399, 7897352, 3703048, 13664521, 1114375, 6848776, 2654472, 11567369, 557320, 8945928,
4751624, 15761673, 262151, 5538056, 1343752, 14877960, 2818823, 7635208, 3440904, 13140233,
852231, 6586632, 2392328, 11043081, 295176, 8683784, 4489480, 15237385, 524295, 6062344,
1868040, 9994505, 5440519, 8159496, 3965192, 14188809, 1507847, 7110920, 2916616, 12091657,
819464, 9208072, 5013768, 16285961, 196615, 5406984, 1212680, 10683656, 2294535, 7504136,
3309832, 12878089, 721159, 6455560, 2261256, 10780937, 164104, 8552712, 4358408, 14975241,
458759, 5931272, 1736968, 9732361, 4391943, 8028424, 3834120, 13926665, 1245703, 6979848,
2785544, 11829513, 688392, 9077000, 4882696, 16023817, 327687, 5669128, 1474824, 16392,
3343111, 7766280, 3571976, 13402377, 983303, 6717704, 2523400, 11305225, 426248, 8814856,
4620552, 15499529, 589831, 6193416, 1999112, 10256649, 6489095, 8290568, 4096264, 14450953,
1769991, 7241992, 3047688, 12353801, 950536, 9339144, 5144840, 16548105, 16391, 5341448,
1147144, 8586504, 2032135, 7438600, 3244296, 12747017, 655367, 6390024, 2195720, 10649865,
98568, 8487176, 4292872, 14844169, 393223, 5865736, 1671432, 9601289, 3867399, 7962888,
3768584, 13795593, 1114375, 6914312, 2720008, 11698441, 622856, 9011464, 4817160, 15892745,
262151, 5603592, 1409288, 16908296, 2818823, 7700744, 3506440, 13271305, 852231, 6652168,
2457864, 11174153, 360712, 8749320, 4555016, 15368457, 524295, 6127880, 1933576, 10125577,
5440519, 8225032, 4030728, 14319881, 1507847, 7176456, 2982152, 12222729, 885000, 9273608,
5079304, 16417033, 196615, 5472520, 1278216, 12780808, 2294535, 7569672, 3375368, 13009161,
721159, 6521096, 2326792, 10912009, 229640, 8618248, 4423944, 15106313, 458759, 5996808,
1802504, 9863433, 4391943, 8093960, 3899656, 14057737, 1245703, 7045384, 2851080, 11960585,
753928, 9142536, 4948232, 16154889, 327687, 5734664, 1540360, 16392, 3343111, 7831816, 3637512,
13533449, 983303, 6783240, 2588936, 11436297, 491784, 8880392, 4686088, 15630601, 589831,
6258952, 2064648, 10387721, 6489095, 8356104, 4161800, 14582025, 1769991, 7307528, 3113224,
12484873, 1016072, 9404680, 5210376, 16679177, 16391, 5275912, 1081608, 7537672, 2032135,
7373064, 3178760, 12681481, 655367, 6324488, 2130184, 10584329, 33032, 8421640, 4227336,
14778633, 393223, 5800200, 1605896, 9535753, 3867399, 7897352, 3703048, 13730057, 1114375,
6848776, 2654472, 11632905, 557320, 8945928, 4751624, 15827209, 262151, 5538056, 1343752,
14877960, 2818823, 7635208, 3440904, 13205769, 852231, 6586632, 2392328, 11108617, 295176,
8683784, 4489480, 15302921, 524295, 6062344, 1868040, 10060041, 5440519, 8159496, 3965192,
14254345, 1507847, 7110920, 2916616, 12157193, 819464, 9208072, 5013768, 16351497, 196615,
5406984, 1212680, 10683656, 2294535, 7504136, 3309832, 12943625, 721159, 6455560, 2261256,
10846473, 164104, 8552712, 4358408, 15040777, 458759, 5931272, 1736968, 9797897, 4391943,
8028424, 3834120, 13992201, 1245703, 6979848, 2785544, 11895049, 688392, 9077000, 4882696,
16089353, 327687, 5669128, 1474824, 16392, 3343111, 7766280, 3571976, 13467913, 983303,
6717704, 2523400, 11370761, 426248, 8814856, 4620552, 15565065, 589831, 6193416, 1999112,
10322185, 6489095, 8290568, 4096264, 14516489, 1769991, 7241992, 3047688, 12419337, 950536,
9339144, 5144840, 16613641, 16391, 5341448, 1147144, 8586504, 2032135, 7438600, 3244296,
12812553, 655367, 6390024, 2195720, 10715401, 98568, 8487176, 4292872, 14909705, 393223,
5865736, 1671432, 9666825, 3867399, 7962888, 3768584, 13861129, 1114375, 6914312, 2720008,
11763977, 622856, 9011464, 4817160, 15958281, 262151, 5603592, 1409288, 16908296, 2818823,
7700744, 3506440, 13336841, 852231, 6652168, 2457864, 11239689, 360712, 8749320, 4555016,
15433993, 524295, 6127880, 1933576, 10191113, 5440519, 8225032, 4030728, 14385417, 1507847,
7176456, 2982152, 12288265, 885000, 9273608, 5079304, 16482569, 196615, 5472520, 1278216,
12780808, 2294535, 7569672, 3375368, 13074697, 721159, 6521096, 2326792, 10977545, 229640,
8618248, 4423944, 15171849, 458759, 5996808, 1802504, 9928969, 4391943, 8093960, 3899656,
14123273, 1245703, 7045384, 2851080, 12026121, 753928, 9142536, 4948232, 16220425, 327687,
5734664, 1540360, 16392, 3343111, 7831816, 3637512, 13598985, 983303, 6783240, 2588936,
11501833, 491784, 8880392, 4686088, 15696137, 589831, 6258952, 2064648, 10453257, 6489095,
8356104, 4161800, 14647561, 1769991, 7307528, 3113224, 12550409, 1016072, 9404680, 5210376,
16744713,
];
pub(crate) const FIXED_DIST_TABLE: [u32; 32] = [
98309, 16877317, 1147653, 268536581, 360709, 67209477, 4293893, 1073843461, 229381, 33654789,
2196485, 536972293, 623109, 134318597, 8488453, 5, 163845, 25265925, 1671941, 402754309,
491781, 100763909, 6391045, 1610714373, 294917, 50432005, 3245061, 805407749, 885253,
201427461, 12682757, 5,
];
#[cfg(test)]
pub(crate) const FIXED_CODE_LENGTHS: [u8; 320] = make_fixed_code_lengths();
#[cfg(test)]
const fn make_fixed_code_lengths() -> [u8; 320] {
let mut i = 0;
let mut lengths = [0; 320];
while i < 144 {
lengths[i] = 8;
i += 1;
}
while i < 256 {
lengths[i] = 9;
i += 1;
}
while i < 280 {
lengths[i] = 7;
i += 1;
}
while i < 288 {
lengths[i] = 8;
i += 1;
}
while i < 320 {
lengths[i] = 5;
i += 1;
}
lengths
}