1use anyhow::{bail, Result};
16
17use crate::stuffit_lzh::BitReader;
18
19const LITLEN_SYMBOLS: usize = 276;
20const DIST_SYMBOLS: usize = 16;
21const HEADER_LEN: usize = 16;
22const MAX_TREE_DEPTH: u32 = 4;
24
25pub fn declared_len(chunk: &[u8]) -> Option<usize> {
27 let b = chunk.get(4..8)?;
28 Some(u32::from_le_bytes([b[0], b[1], b[2], b[3]]) as usize)
29}
30
31pub fn decompress(chunk: &[u8], max_out: usize) -> Result<Vec<u8>> {
33 if chunk.len() < HEADER_LEN {
34 bail!("ShrinkWrap: chunk shorter than its 16-byte header");
35 }
36 let want = declared_len(chunk).unwrap_or(0);
37 if want > max_out {
38 bail!("ShrinkWrap: chunk declares {want} bytes, more than the {max_out} it may hold");
39 }
40 let mut len_base = [0u32; 20];
41 let mut len_extra = [0u32; 20];
42 let mut k = 0u32;
43 for i in 0..20 {
44 len_extra[i] = if i >= 2 { (i as u32 - 2) >> 1 } else { 0 };
45 len_base[i] = k + 4;
46 k += 1 << len_extra[i];
47 }
48 let mut dist_base = [0u32; 16];
49 let mut k = 1u32;
50 for (i, base) in dist_base.iter_mut().enumerate() {
51 *base = k;
52 k += 1 << i;
53 }
54
55 let mut br = BitReader::new(&chunk[HEADER_LEN..]);
56 let litlen = read_tree(&mut br, LITLEN_SYMBOLS, 0)?;
57 let dist = read_tree(&mut br, DIST_SYMBOLS, 0)?;
58
59 let mut out = Vec::with_capacity(want);
60 while out.len() < want {
61 let sym = walk(&mut br, litlen.as_slice(), LITLEN_SYMBOLS)?;
62 if sym < 256 {
63 out.push(sym as u8);
64 continue;
65 }
66 let li = sym - 256;
67 if li >= 20 {
68 bail!("ShrinkWrap: length symbol {li} out of range");
69 }
70 let mut len = len_base[li] + br.next_bits(len_extra[li]);
71 let di = walk(&mut br, dist.as_slice(), DIST_SYMBOLS)?;
72 let distance = dist_base[di] as usize + br.next_bits(di as u32) as usize;
73 if distance == 0 || distance > out.len() {
74 bail!(
75 "ShrinkWrap: back-reference {distance} before the start of the output ({})",
76 out.len()
77 );
78 }
79 while len > 0 && out.len() < want {
80 let b = out[out.len() - distance];
81 out.push(b);
82 len -= 1;
83 }
84 }
85 Ok(out)
86}
87
88fn walk(br: &mut BitReader, tree: &[u16], symbols: usize) -> Result<usize> {
90 let leaf = symbols * 2;
91 let mut node = 0usize;
92 for _ in 0..=32 {
93 node = match tree.get(node + br.next_bit() as usize) {
94 Some(&n) if n != 0 => n as usize,
95 _ => bail!("ShrinkWrap: invalid Huffman code in the stream"),
96 };
97 if node >= leaf {
98 return Ok(node - leaf);
99 }
100 }
101 bail!("ShrinkWrap: Huffman code longer than 32 bits")
102}
103
104fn read_tree(br: &mut BitReader, codesize: usize, depth: u32) -> Result<Vec<u16>> {
106 let zero_flag = br.next_bits(1);
107 let width = br.next_bits(2) + 2;
108 let offset = br.next_bits(3) + 1;
109 let size = 1usize << width;
110 let repeat = size - 1;
111 let absent = if zero_flag != 0 {
113 Some(repeat - 1)
114 } else {
115 None
116 };
117 let mut code = vec![0u8; codesize];
118 let mut i = 0usize;
119 if br.next_bits(2) & 1 != 0 {
120 if depth >= MAX_TREE_DEPTH {
121 bail!("ShrinkWrap: code-length trees nested too deeply");
122 }
123 let sub = read_tree(br, size, depth + 1)?;
124 while i < codesize {
125 let l = walk(br, sub.as_slice(), size)?;
126 if Some(l) == absent {
127 code[i] = 0;
128 i += 1;
129 } else if l == repeat {
130 let n = walk(br, sub.as_slice(), size)? + 3;
131 i = repeat_previous(code.as_mut_slice(), i, n)?;
132 } else {
133 code[i] = (l as u32 + offset) as u8;
134 i += 1;
135 }
136 }
137 } else {
138 while i < codesize {
139 let l = br.next_bits(width) as usize;
140 if Some(l) == absent {
141 code[i] = 0;
142 i += 1;
143 } else if l == repeat {
144 let n = br.next_bits(width) as usize + 3;
145 i = repeat_previous(code.as_mut_slice(), i, n)?;
146 } else {
147 code[i] = (l as u32 + offset) as u8;
148 i += 1;
149 }
150 }
151 }
152 let tree = build_tree(code.as_slice())?;
153 br.align_to_byte();
154 Ok(tree)
155}
156
157fn repeat_previous(code: &mut [u8], i: usize, n: usize) -> Result<usize> {
159 if i == 0 {
160 bail!("ShrinkWrap: code-length repeat with no previous length");
161 }
162 let end = (i + n).min(code.len());
163 let prev = code[i - 1];
164 for c in &mut code[i..end] {
165 *c = prev;
166 }
167 Ok(end)
168}
169
170fn build_tree(code: &[u8]) -> Result<Vec<u16>> {
172 let n = code.len();
173 if code.iter().any(|&c| c > 32) {
174 bail!("ShrinkWrap: code length over 32 bits");
175 }
176 let mut sorted = code.to_vec();
177 let mut order: Vec<u16> = (0..n as u16).collect();
178 sort_codes(0, n, sorted.as_mut_slice(), order.as_mut_slice());
179
180 let mut bits = vec![0u64; n];
181 let mut i = sorted.iter().position(|&c| c != 0).unwrap_or(n);
182 let mut j = 0u64;
183 while i < n {
184 if i > 0 {
185 j <<= sorted[i] - sorted[i - 1];
186 }
187 let mut m = 0u64;
188 let mut l = j;
189 for _ in 0..sorted[i] {
190 m = (m << 1) | (l & 1);
191 l >>= 1;
192 }
193 bits[order[i] as usize] = m;
194 i += 1;
195 j += 1;
196 }
197
198 let mut tree = vec![0u16; n * 2];
199 let mut next = 2usize;
200 for (sym, &len) in code.iter().enumerate() {
201 let mut node = 0usize;
202 let mut m = bits[sym];
203 for k in 0..len {
204 node += (m & 1) as usize;
205 let slot = match tree.get_mut(node) {
206 Some(s) => s,
207 None => bail!("ShrinkWrap: over-subscribed Huffman code"),
208 };
209 if k + 1 == len {
210 *slot = (n * 2 + sym) as u16;
211 } else {
212 if *slot == 0 {
213 if next >= n * 2 {
214 bail!("ShrinkWrap: Huffman code needs more nodes than it has symbols");
215 }
216 *slot = next as u16;
217 next += 2;
218 }
219 node = *slot as usize;
220 }
221 m >>= 1;
222 }
223 }
224 Ok(tree)
225}
226
227fn sort_codes(mut first: usize, mut last: usize, code: &mut [u8], order: &mut [u16]) {
229 while last - first > 1 {
230 let mut i = first;
231 let mut j = last;
232 loop {
233 i += 1;
234 while i < last && code[first] > code[i] {
235 i += 1;
236 }
237 j -= 1;
238 while j > first && code[first] < code[j] {
239 j -= 1;
240 }
241 if j > i {
242 code.swap(i, j);
243 order.swap(i, j);
244 } else {
245 break;
246 }
247 }
248 if first != j {
249 code.swap(first, j);
250 order.swap(first, j);
251 let i = j + 1;
252 if last - i <= j - first {
253 sort_codes(i, last, code, order);
254 last = j;
255 } else {
256 sort_codes(first, j, code, order);
257 first = i;
258 }
259 } else {
260 first += 1;
261 }
262 }
263}
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 struct BitWriter {
271 out: Vec<u8>,
272 acc: u32,
273 n: u32,
274 }
275
276 impl BitWriter {
277 fn put(&mut self, v: u32, bits: u32) {
278 for b in 0..bits {
279 self.acc |= ((v >> b) & 1) << self.n;
280 self.n += 1;
281 if self.n == 8 {
282 self.out.push(self.acc as u8);
283 self.acc = 0;
284 self.n = 0;
285 }
286 }
287 }
288 fn align(&mut self) {
289 if self.n > 0 {
290 self.out.push(self.acc as u8);
291 self.acc = 0;
292 self.n = 0;
293 }
294 }
295 }
296
297 fn codes_for(lengths: &[u8]) -> Vec<u64> {
299 let n = lengths.len();
300 let mut sorted = lengths.to_vec();
301 let mut order: Vec<u16> = (0..n as u16).collect();
302 sort_codes(0, n, &mut sorted, &mut order);
303 let mut bits = vec![0u64; n];
304 let mut i = sorted.iter().position(|&c| c != 0).unwrap_or(n);
305 let mut j = 0u64;
306 while i < n {
307 if i > 0 {
308 j <<= sorted[i] - sorted[i - 1];
309 }
310 let (mut m, mut l) = (0u64, j);
311 for _ in 0..sorted[i] {
312 m = (m << 1) | (l & 1);
313 l >>= 1;
314 }
315 bits[order[i] as usize] = m;
316 i += 1;
317 j += 1;
318 }
319 bits
320 }
321
322 fn put_flat_tree(w: &mut BitWriter, lengths: &[u8], width: u32) {
324 w.put(0, 1); w.put(width - 2, 2);
326 w.put(0, 3); w.put(0, 2); for &l in lengths {
329 w.put(l as u32 - 1, width);
330 }
331 w.align();
332 }
333
334 #[test]
336 fn round_trips_literals_and_a_match() {
337 let litlen: Vec<u8> = (0..LITLEN_SYMBOLS)
339 .map(|s| if s < 236 { 8 } else { 9 })
340 .collect();
341 let dist: Vec<u8> = vec![4; DIST_SYMBOLS];
342 let (lc, dc) = (codes_for(&litlen), codes_for(&dist));
343 let mut w = BitWriter {
344 out: Vec::new(),
345 acc: 0,
346 n: 0,
347 };
348 put_flat_tree(&mut w, &litlen, 4);
349 put_flat_tree(&mut w, &dist, 3);
350 let text = b"NDIF chunk, ";
351 for &b in text.iter() {
352 w.put(lc[b as usize] as u32, 8);
353 }
354 w.put(lc[258] as u32, 9);
356 w.put(dc[3] as u32, 4);
357 w.put(4, 3);
358 w.align();
359
360 let mut expect = text.to_vec();
361 for _ in 0..6 {
362 expect.push(expect[expect.len() - 12]);
363 }
364 let mut chunk = (w.out.len() as u32 + 16).to_le_bytes().to_vec();
365 chunk.extend_from_slice(&(expect.len() as u32).to_le_bytes());
366 chunk.extend_from_slice(&(expect.len() as u32).to_le_bytes());
367 chunk.extend_from_slice(&[0xff; 4]);
368 chunk.extend_from_slice(&w.out);
369 assert_eq!(decompress(&chunk, 1 << 20).unwrap(), expect);
370 assert!(decompress(&chunk, 4).is_err(), "over the caller's cap");
371 assert!(
372 decompress(&chunk[..10], 1 << 20).is_err(),
373 "truncated header"
374 );
375 }
376
377 #[test]
379 fn garbage_errors_cleanly() {
380 let mut chunk = vec![
381 0u8, 0, 0, 0, 0, 0x10, 0, 0, 0, 0x10, 0, 0, 0xff, 0xff, 0xff, 0xff,
382 ];
383 chunk.extend((0..200u32).map(|i| (i.wrapping_mul(37) ^ 0x5a) as u8));
384 let _ = decompress(&chunk, 1 << 20);
385 let _ = decompress(&[0u8; 16], 1 << 20);
386 }
387}