if max == 0 { // no symbols to code at all let code = Code {
op: 64,
bits: 1,
val: 0,
};
table[0] = code;
table[1] = code;
return InflateTable::Success(1);
}
/* check for an over-subscribed or incomplete set of lengths */ letmut left = 1i32; letmut len = 1; while len <= MAX_BITS {
left <<= 1;
left -= count[len] as i32; if left < 0 { // over-subscribed return InflateTable::InvalidCode;
}
len += 1;
}
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[0..codes].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),
};
let 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 letmut used = 1 << 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] as u8,
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_); let min = 1 << curr; // also has the name 'fill' in the C code
let base = &mut table[next + (huff >> drop_)..]; for fill in (0..min).step_by(incr) {
base[fill] = here;
}
// 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)
}
#[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.