Skip to main content

chapter_tgz/
decode.rs

1pub(crate) const fn prefix(bfinal: bool) -> [u8; 9] {
2    [
3        0b00000100 | bfinal as u8,
4        0b11000000,
5        0b00010001,
6        0b00000001,
7        0b00000000,
8        0b00000000,
9        0b00000000,
10        0b00000000,
11        0b00100000,
12    ]
13}
14
15pub(crate) fn decode_from_end(bytes: &[u8]) -> Option<(usize, u64)> {
16    let prefix = prefix(true);
17    let mut start = bytes.len().checked_sub(13)?;
18    while !bytes[start..].starts_with(&prefix) {
19        start = start.checked_sub(1)?;
20    }
21    let payload = decode_rest(&bytes[start + prefix.len()..])?;
22    Some((start, payload))
23}
24
25pub(crate) fn decode_from_start(bytes: &[u8]) -> Option<u64> {
26    let prefix = prefix(false);
27    if bytes.starts_with(&prefix) {
28        decode_rest(&bytes[prefix.len()..])
29    } else {
30        None
31    }
32}
33
34fn decode_rest(bytes: &[u8]) -> Option<u64> {
35    let mut bitpos = 0;
36    let mut take = |n: usize| -> u8 {
37        let byte = (bytes.get(bitpos / 8).unwrap_or(&0) >> (bitpos % 8))
38            | bytes
39                .get(bitpos / 8 + 1)
40                .unwrap_or(&0)
41                .unbounded_shl((8 - bitpos % 8) as u32);
42        bitpos += n;
43        byte & 0b11111111u8.unbounded_shr((8 - n) as u32)
44    };
45
46    let mut payload = 0;
47    let mut zeros = 0;
48    for i in 0..22 {
49        if i > 0 && take(1) != 0 {
50            break;
51        }
52        let n = take(3);
53        payload |= u64::from(n) << (i * 3);
54        zeros += 3 + n as usize;
55    }
56
57    if (payload < 0x8000_0000_0000_0000 || take(1) == 1)
58        && take(1) == 1
59        && match zeros {
60            4..=97 => {
61                take(7) == 0b1111111
62                    && take(2) == 0b11
63                    && take(7) == (256 - (zeros + 138) - 11) as u8
64            }
65            98..=107 => {
66                take(7) == (256 - (zeros + 20) - 11) as u8
67                    && take(1) == 0
68                    && take(3) == 0b111
69                    && take(1) == 0
70                    && take(3) == 0b111
71            }
72            108..=117 => {
73                take(7) == (256 - (zeros + 10) - 11) as u8 && take(1) == 0 && take(3) == 0b111
74            }
75            118..=214 => take(7) == (256 - zeros - 11) as u8,
76            0..=3 | 215.. => false,
77        }
78        && take(2) == 1
79        && take(2) == 1
80        && take(1) == 0
81    {
82        Some(payload)
83    } else {
84        None
85    }
86}