use crate::block::{LL_SPEC, ML_SPEC, OF_SPEC};
use crate::error::Error;
use crate::huffman_encode::{self, HufRepeat};
use crate::literals_encode::HufState;
use crate::sequences_encode::{FseEntropyState, FseRepeat};
use crate::{fse, fse_encode};
fn highbit32(x: u32) -> u32 {
debug_assert!(x >= 1);
31 - x.leading_zeros()
}
pub(crate) struct DictCEntropy {
pub(crate) entropy: FseEntropyState,
pub(crate) rep: [u32; 3],
pub(crate) dict_id: u32,
pub(crate) entropy_size: usize,
}
fn dict_ncount_repeat(norm: &[i16], dict_max_symbol: u32, max_symbol: u32) -> FseRepeat {
if dict_max_symbol < max_symbol {
return FseRepeat::Check;
}
if norm[..=max_symbol as usize].contains(&0) {
return FseRepeat::Check;
}
FseRepeat::Valid
}
pub(crate) fn load_c_entropy(dict: &[u8]) -> Result<DictCEntropy, Error> {
let corrupt = Error::DictionaryCorrupted;
let dict_id = u32::from_le_bytes(dict.get(4..8).ok_or(corrupt)?.try_into().unwrap());
let mut pos = 8usize;
let (huf_ct, has_zero_weights, used) =
huffman_encode::read_ctable(dict.get(pos..).ok_or(corrupt)?).map_err(|_| corrupt)?;
let huf_repeat = if !has_zero_weights && huf_ct.max_symbol == 255 {
HufRepeat::Valid
} else {
HufRepeat::Check
};
pos += used;
let of_nc = fse::read_ncount(
dict.get(pos..).ok_or(corrupt)?,
OF_SPEC.max_symbol,
OF_SPEC.max_log,
)
.map_err(|_| corrupt)?;
let of_dict_max = (of_nc.counts.len() - 1) as u32;
let mut of_norm = of_nc.counts;
of_norm.resize(OF_SPEC.max_symbol as usize + 1, 0);
let of_ct = fse_encode::build_ctable(&of_norm, OF_SPEC.max_symbol, of_nc.table_log);
pos += of_nc.bytes_consumed;
let ml_nc = fse::read_ncount(
dict.get(pos..).ok_or(corrupt)?,
ML_SPEC.max_symbol,
ML_SPEC.max_log,
)
.map_err(|_| corrupt)?;
let ml_dict_max = (ml_nc.counts.len() - 1) as u32;
let ml_ct = fse_encode::build_ctable(&ml_nc.counts, ml_dict_max, ml_nc.table_log);
let ml_repeat = dict_ncount_repeat(&ml_nc.counts, ml_dict_max, ML_SPEC.max_symbol);
pos += ml_nc.bytes_consumed;
let ll_nc = fse::read_ncount(
dict.get(pos..).ok_or(corrupt)?,
LL_SPEC.max_symbol,
LL_SPEC.max_log,
)
.map_err(|_| corrupt)?;
let ll_dict_max = (ll_nc.counts.len() - 1) as u32;
let ll_ct = fse_encode::build_ctable(&ll_nc.counts, ll_dict_max, ll_nc.table_log);
let ll_repeat = dict_ncount_repeat(&ll_nc.counts, ll_dict_max, LL_SPEC.max_symbol);
pos += ll_nc.bytes_consumed;
let reps = dict.get(pos..pos + 12).ok_or(corrupt)?;
let mut rep = [0u32; 3];
for (i, slot) in rep.iter_mut().enumerate() {
*slot = u32::from_le_bytes(reps[4 * i..4 * i + 4].try_into().unwrap());
}
pos += 12;
let entropy_size = pos;
let dict_content_size = dict.len() - entropy_size;
let mut offcode_max = OF_SPEC.max_symbol;
if dict_content_size as u64 <= u64::from(u32::MAX) - 128 * 1024 {
let max_offset = (dict_content_size as u32).wrapping_add(128 * 1024);
offcode_max = highbit32(max_offset);
}
let of_repeat = dict_ncount_repeat(&of_norm, of_dict_max, offcode_max.min(OF_SPEC.max_symbol));
for &r in &rep {
if r == 0 || r as usize > dict_content_size {
return Err(corrupt);
}
}
Ok(DictCEntropy {
entropy: FseEntropyState {
huf: HufState {
table: Some(huf_ct),
repeat: huf_repeat,
},
ll: Some(ll_ct),
ll_repeat,
of: Some(of_ct),
of_repeat,
ml: Some(ml_ct),
ml_repeat,
},
rep,
dict_id,
entropy_size,
})
}