Coverage Report

Created: 2026-08-31 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/data-encoding/lib/fuzz/src/spec.rs
Line
Count
Source
1
//! Reference implementation of the specification.
2
3
use data_encoding::{BitOrder, Specification};
4
5
9.07k
pub fn encode(spec: &Specification, input: &[u8]) -> String {
6
    // Make sure the specification is valid.
7
9.07k
    assert!(spec.encoding().is_ok());
8
    // Define short variables.
9
9.07k
    let symbols = spec.symbols.as_bytes();
10
9.07k
    let bit = symbols.len().trailing_zeros() as usize;
11
9.07k
    let msb = spec.bit_order == BitOrder::MostSignificantFirst;
12
    // Convert from base256 to binary and from binary to baseX.
13
9.07k
    let mut output = bits_value(bit, msb, &value_bits(8, msb, input));
14
    // Convert from values to symbols.
15
833M
    output.iter_mut().for_each(|x| *x = symbols[*x as usize]);
16
    // Pad to the next `dec(bit)` boundary, if needed.
17
9.07k
    if let Some(pad) = spec.padding {
18
7.88k
        while !output.len().is_multiple_of(dec(bit)) {
19
5.44k
            output.push(pad as u8);
20
5.44k
        }
21
6.63k
    }
22
    // Wrap every `width` bytes with `separator`, if needed. Including a possibly partial last row.
23
9.07k
    if spec.wrap.width != 0 {
24
25.9M
        for row in std::mem::take(&mut output).chunks(spec.wrap.width) {
25
25.9M
            output.extend_from_slice(row);
26
25.9M
            output.extend_from_slice(spec.wrap.separator.as_bytes());
27
25.9M
        }
28
3.44k
    }
29
    // Cast the symbols to a string.
30
9.07k
    String::from_utf8(output).unwrap()
31
9.07k
}
32
33
8.65k
pub fn decode(spec: &Specification, input: &[u8]) -> Option<Vec<u8>> {
34
    // Make sure the specification is valid.
35
8.65k
    assert!(spec.encoding().is_ok());
36
    // Define short variables.
37
8.65k
    let symbols = spec.symbols.as_bytes();
38
8.65k
    let bit = symbols.len().trailing_zeros() as usize;
39
8.65k
    let xlate = &spec.translate;
40
    // Make sure we also ignore the separators.
41
8.65k
    let mut ignore = spec.ignore.as_bytes().to_vec();
42
8.65k
    ignore.extend_from_slice(spec.wrap.separator.as_bytes());
43
    // Translate and ignore bytes as needed. Only symbols and padding are left (for valid input).
44
8.65k
    let input: Vec<u8> = input
45
8.65k
        .iter()
46
2.97G
        .map(|&x| xlate.from.bytes().position(|y| y == x).map_or(x, |i| xlate.to.as_bytes()[i]))
47
442M
        .filter(|x| !ignore.contains(x))
48
8.65k
        .collect();
49
    // Decode by blocks of `dec(bit)` bytes. Only the last one may be partial.
50
8.65k
    let mut output = Vec::new();
51
9.90M
    for block in input.chunks(dec(bit)) {
52
9.90M
        output.extend_from_slice(&decode_block(spec, block)?);
53
    }
54
1.33k
    Some(output)
55
8.65k
}
56
57
9.90M
fn decode_block(spec: &Specification, mut input: &[u8]) -> Option<Vec<u8>> {
58
    // Define short variables.
59
9.90M
    let bit = spec.symbols.len().trailing_zeros() as usize;
60
9.90M
    let msb = spec.bit_order == BitOrder::MostSignificantFirst;
61
    // Remove padding, if needed.
62
9.90M
    if let Some(pad) = spec.padding {
63
        // There are no partial blocks with padding.
64
1.77M
        if input.len() != dec(bit) {
65
1.09k
            return None;
66
1.77M
        }
67
        // Repeatedly remove last byte, if padding.
68
2.01M
        while *input.last()? == pad as u8 {
69
237k
            input = &input[.. input.len() - 1];
70
237k
        }
71
8.12M
    }
72
    // Convert from symbols to values.
73
46.6M
    let input = input.iter().map(|&x| value_symbol(spec, x)).collect::<Option<Vec<u8>>>()?;
74
    // Convert from baseX to binary.
75
9.89M
    let mut bits = value_bits(bit, msb, &input);
76
    // Check trailing bits (leading bits of the binary number that don't form a full byte).
77
9.89M
    let trail = bits.len() % 8;
78
9.89M
    if 0 < trail {
79
        // The trailing bits should not contain a full symbol.
80
55.9k
        if bit <= trail {
81
494
            return None;
82
55.4k
        }
83
        // The trailing bits should be zero, if checked.
84
55.4k
        let trail = bits.split_off(bits.len() - trail);
85
55.4k
        if spec.check_trailing_bits && trail.iter().any(|x| *x) {
86
272
            return None;
87
55.1k
        }
88
9.83M
    }
89
    // A block cannot be composed of padding only.
90
9.89M
    if bits.is_empty() {
91
0
        return None;
92
9.89M
    }
93
    // Convert from binary to base256.
94
9.89M
    Some(bits_value(8, msb, &bits))
95
9.90M
}
96
97
46.6M
fn value_symbol(spec: &Specification, symbol: u8) -> Option<u8> {
98
    // The value of a symbol is its position in the specification.
99
623M
    spec.symbols.bytes().position(|x| x == symbol).map(|x| x as u8)
100
46.6M
}
101
102
9.90M
fn value_bits(bit: usize, msb: bool, input: &[u8]) -> Vec<bool> {
103
    // Convert from binary to baseX.
104
9.90M
    let mut output = Vec::new();
105
385M
    for &x in input {
106
2.83G
        for i in order(msb, bit) {
107
2.83G
            output.push(x & (1 << i) != 0);
108
2.83G
        }
109
    }
110
9.90M
    output
111
9.90M
}
112
113
9.90M
fn bits_value(bit: usize, msb: bool, input: &[bool]) -> Vec<u8> {
114
    // Convert from baseX to binary.
115
9.90M
    let mut output = Vec::new();
116
858M
    for bits in input.chunks(bit) {
117
2.83G
        output.push(order(msb, bit).zip(bits).map(|(i, &b)| (b as u8) << i).sum());
118
    }
119
9.90M
    output
120
9.90M
}
121
122
1.23G
fn order(msb: bool, n: usize) -> Box<dyn Iterator<Item = usize>> {
123
    // Iterate from 0 to n - 1, or the opposite if most significant bit first.
124
1.23G
    if msb {
125
623M
        Box::new((0 .. n).rev())
126
    } else {
127
611M
        Box::new(0 .. n)
128
    }
129
1.23G
}
130
131
1.79M
fn enc(bit: usize) -> usize {
132
    // Input block size for encoding, output block size for decoding.
133
1.79M
    match bit {
134
2.57k
        1 | 2 | 4 => 1,
135
924k
        3 | 6 => 3,
136
863k
        5 => 5,
137
0
        _ => unreachable!(),
138
    }
139
1.79M
}
140
141
1.79M
fn dec(bit: usize) -> usize {
142
    // Input block size for decoding, output block size for encoding.
143
1.79M
    enc(bit) * 8 / bit
144
1.79M
}
145
146
#[cfg(test)]
147
mod tests {
148
    use super::*;
149
150
    #[test]
151
    fn value_bits_ok() {
152
        #[track_caller]
153
        fn test(bit: usize, msb: bool, values: &[u8], bits: &[u8]) {
154
            let bits: Vec<_> = bits.into_iter().map(|&x| x == 1).collect();
155
            assert_eq!(value_bits(bit, msb, values), bits);
156
            assert_eq!(bits_value(bit, msb, &bits), values);
157
        }
158
        test(8, true, &[0xc5, 0x69], &[1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1]);
159
        test(8, false, &[0xc5, 0x69], &[1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0]);
160
        test(6, true, &[0x36, 0x2c], &[1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0]);
161
        test(6, false, &[0x36, 0x2c], &[0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1]);
162
    }
163
}