bazaar_groupcompress/
lib.rs1pub 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}