pub(crate) fn inflate_table(
codetype: CodeType,
lens: &[u16],
table: &mut [Code],
bits: usize,
work: &mut [u16],
) -> InflateTable { // number of codes of each length letmut count = [0u16; MAX_BITS + 1];
let (mut min, mut max) = (MAX_BITS, 0); for &len in lens { if len > 0 {
count[len as usize] += 1;
max = Ord::max(max, usize::from(len));
min = Ord::min(min, usize::from(len));
}
}
if max == 0 { // no symbols to code at all let code = Code {
op: 64,
bits: 1,
val: 0,
};
// NOTE: if max != 0, then min has been set to a value <= max. let root = bits.clamp(min, max);
/* check for an over-subscribed or incomplete set of lengths */ letmut left = 1u32; for &sym in &count[1..] {
left = match (left << 1).checked_sub(u32::from(sym)) {
None => return InflateTable::InvalidCode, // over-subscribed
Some(v) => v,
};
}
if left > 0 && (matches!(codetype, CodeType::Codes) || max != 1) { // incomplete set return InflateTable::InvalidCode;
}
/* generate offsets into symbol table for each length for sorting */
// offsets in table for each length letmut offs = [0u16; MAX_BITS + 1]; for len in1..MAX_BITS {
offs[len + 1] = offs[len] + count[len];
}
/* sort symbols by length, by symbol order within each length */ for (sym, len) in lens.iter().copied().enumerate() { if len != 0 { let offset = offs[len as usize];
offs[len as usize] += 1;
work[offset as usize] = sym as u16;
}
}
let (base, extra, match_) = match codetype {
CodeType::Codes => (&[] as &[_], &[] as &[_], 20),
CodeType::Lens => (&LBASE[..], &LEXT[..], 257),
CodeType::Dists => (&DBASE[..], &DEXT[..], 0),
};
letmut used = 1 << root;
/* check available table space */ if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS { return InflateTable::EnoughIsNotEnough;
}
if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS { return InflateTable::EnoughIsNotEnough;
}
letmut huff = 0; // starting code letmut reversed_huff = 0u32; // starting code, reversed letmut sym = 0; letmut len = min; letmut next = 0usize; // index into `table` letmut curr = root; letmut drop_ = 0; letmut low = usize::MAX; // trigger new subtable when len > root let mask = used - 1; /* mask for comparing low */
// process all codes and make table entries 'outer: loop { // create table entry let here = if work[sym] >= match_ {
Code {
bits: (len - drop_) as u8,
op: extra[(work[sym] - match_) as usize],
val: base[(work[sym] - match_) as usize],
}
} elseif work[sym] + 1 < match_ {
Code {
bits: (len - drop_) as u8,
op: 0,
val: work[sym],
}
} else {
Code {
bits: (len - drop_) as u8,
op: 0b01100000,
val: 0,
}
};
// replicate for those indices with low len bits equal to huff let incr = 1 << (len - drop_); letmut fill = 1 << curr; let min = fill;
// backwards increment the len-bit code huff
reversed_huff = reversed_huff.wrapping_add(0x80000000u32 >> (len - 1));
huff = reversed_huff.reverse_bits() as usize;
// go to next symbol, update count, len
sym += 1;
count[len] -= 1; if count[len] == 0 { if len == max { break'outer;
}
len = lens[work[sym] as usize] as usize;
}
// create new sub-table if needed if len > root && (huff & mask) != low { /* if first time, transition to sub-tables */ if drop_ == 0 {
drop_ = root;
}
/* increment past last table */
next += min; /* here min is 1 << curr */
/* determine length of next table */
curr = len - drop_; letmut left = 1 << curr; while curr + drop_ < max {
left -= count[curr + drop_] as i32; if left <= 0 { break;
}
curr += 1;
left <<= 1;
}
/* check for enough space */
used += 1usize << curr;
if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS { return InflateTable::EnoughIsNotEnough;
}
if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS { return InflateTable::EnoughIsNotEnough;
}
/* point entry in root table to sub-table */
low = huff & mask;
table[low] = Code {
op: curr as u8,
bits: root as u8,
val: next as u16,
};
}
}
/* fill in remaining table entry if code is incomplete (guaranteed to have atmostoneremainingentry,sinceifthecodeisincomplete,the
maximum code length that was allowed to get this far is one bit) */ if huff != 0 { let here = Code {
op: 64,
bits: (len - drop_) as u8,
val: 0,
};
table[next..][huff] = here;
}
/* set return parameters */
InflateTable::Success { root, used }
}
#[cfg(test)] mod test { usesuper::*;
#[test] fn not_enough_errors() { // we need to call inflate_table() directly in order to manifest // not-enough errors, since zlib insures that enough is always enough
let table = [Code::default(); crate::ENOUGH_DISTS];
letmut work = [0; 16]; letmut lens: [_; 16] = core::array::from_fn(|i| (i + 1) as u16);
lens[15] = 15;
letmut next = table; let bits = 15; let ret = inflate_table(CodeType::Dists, &lens[..16], &mut next, bits, &mut work);
assert_eq!(ret, InflateTable::EnoughIsNotEnough);
letmut next = table; let bits = 1; let ret = inflate_table(CodeType::Dists, &lens[..16], &mut next, bits, &mut work);
assert_eq!(ret, InflateTable::EnoughIsNotEnough);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.