bazaar_groupcompress/
lib.rs

1pub fn encode_base128_int(mut val: u128) -> Vec<u8> {
2    let mut data = Vec::new();
3    while val >= 0x80 {
4        data.push(((val | 0x80) & 0xFF) as u8);
5        val >>= 7;
6    }
7    data.push(val as u8);
8    data
9}
10
11pub fn decode_base128_int(data: &[u8]) -> (u128, usize) {
12    let mut offset = 0;
13    let mut val: u128 = 0;
14    let mut shift = 0;
15    let mut bval = data[offset];
16    while bval >= 0x80 {
17        val |= ((bval & 0x7F) as u128) << shift;
18        shift += 7;
19        offset += 1;
20        bval = data[offset];
21    }
22    val |= (bval as u128) << shift;
23    offset += 1;
24    (val, offset)
25}
26
27pub type CopyInstruction = (usize, usize, usize);
28
29pub fn decode_copy_instruction(data: &[u8], cmd: u8, pos: usize) -> Result<CopyInstruction, String> {
30    if cmd & 0x80 != 0x80 {
31        return Err("copy instructions must have bit 0x80 set".to_string());
32    }
33    let mut offset = 0;
34    let mut length = 0;
35    let mut new_pos = pos;
36
37    if cmd & 0x01 != 0 {
38        offset = data[new_pos] as usize;
39        new_pos += 1;
40    }
41    if cmd & 0x02 != 0 {
42        offset |= (data[new_pos] as usize) << 8;
43        new_pos += 1;
44    }
45    if cmd & 0x04 != 0 {
46        offset |= (data[new_pos] as usize) << 16;
47        new_pos += 1;
48    }
49    if cmd & 0x08 != 0 {
50        offset |= (data[new_pos] as usize) << 24;
51        new_pos += 1;
52    }
53    if cmd & 0x10 != 0 {
54        length = data[new_pos] as usize;
55        new_pos += 1;
56    }
57    if cmd & 0x20 != 0 {
58        length |= (data[new_pos] as usize) << 8;
59        new_pos += 1;
60    }
61    if cmd & 0x40 != 0 {
62        length |= (data[new_pos] as usize) << 16;
63        new_pos += 1;
64    }
65    if length == 0 {
66        length = 65536;
67    }
68
69    Ok((offset, length, new_pos))
70}
71
72pub fn apply_delta(basis: &[u8], delta: &[u8]) -> Result<Vec<u8>, String> {
73    let (target_length, mut pos) = decode_base128_int(delta);
74    let mut lines = Vec::new();
75    let len_delta = delta.len();
76
77    while pos < len_delta {
78        let cmd = delta[pos];
79        pos += 1;
80
81        if cmd & 0x80 != 0 {
82            let (offset, length, new_pos) = decode_copy_instruction(delta, cmd, pos)?;
83            pos = new_pos;
84            let last = offset + length;
85            if last > basis.len() {
86                return Err("data would copy bytes past the end of source".to_string());
87            }
88            lines.extend_from_slice(&basis[offset..last]);
89        } else {
90            if cmd == 0 {
91                return Err("Command == 0 not supported yet".to_string());
92            }
93            lines.extend_from_slice(&delta[pos..pos + cmd as usize]);
94            pos += cmd as usize;
95        }
96    }
97
98    if lines.len() != target_length as usize {
99        return Err(format!(
100            "Delta claimed to be {} long, but ended up {} long",
101            target_length,
102            lines.len()
103        ));
104    }
105
106    Ok(lines)
107}
108
109pub fn apply_delta_to_source(source: &[u8], delta_start: usize, delta_end: usize) -> Result<Vec<u8>, String> {
110    let source_size = source.len();
111    if delta_start >= source_size {
112        return Err("delta starts after source".to_string());
113    }
114    if delta_end > source_size {
115        return Err("delta ends after source".to_string());
116    }
117    if delta_start >= delta_end {
118        return Err("delta starts after it ends".to_string());
119    }
120    let delta_bytes = &source[delta_start..delta_end];
121    apply_delta(source, delta_bytes)
122}