1pub mod apply {
3 #[derive(thiserror::Error, Debug)]
5 #[allow(missing_docs)]
6 pub enum Error {
7 #[error("Encountered unsupported command code: 0")]
8 UnsupportedCommandCode,
9 #[error("Delta copy from base: byte slices must match")]
10 DeltaCopyBaseSliceMismatch,
11 #[error("Delta copy data: byte slices must match")]
12 DeltaCopyDataSliceMismatch,
13 }
14}
15
16pub(crate) fn decode_header_size(d: &[u8]) -> (u64, usize) {
19 let mut i = 0;
20 let mut size = 0u64;
21 let mut consumed = 0;
22 for cmd in d.iter() {
23 consumed += 1;
24 size |= (u64::from(*cmd) & 0x7f) << i;
25 i += 7;
26 if *cmd & 0x80 == 0 {
27 break;
28 }
29 }
30 (size, consumed)
31}
32
33pub(crate) fn apply(base: &[u8], mut target: &mut [u8], data: &[u8]) -> Result<(), apply::Error> {
34 let mut i = 0;
35 while let Some(cmd) = data.get(i) {
36 i += 1;
37 match cmd {
38 cmd if cmd & 0b1000_0000 != 0 => {
39 let (mut ofs, mut size): (u32, u32) = (0, 0);
40 if cmd & 0b0000_0001 != 0 {
41 ofs = u32::from(data[i]);
42 i += 1;
43 }
44 if cmd & 0b0000_0010 != 0 {
45 ofs |= u32::from(data[i]) << 8;
46 i += 1;
47 }
48 if cmd & 0b0000_0100 != 0 {
49 ofs |= u32::from(data[i]) << 16;
50 i += 1;
51 }
52 if cmd & 0b0000_1000 != 0 {
53 ofs |= u32::from(data[i]) << 24;
54 i += 1;
55 }
56 if cmd & 0b0001_0000 != 0 {
57 size = u32::from(data[i]);
58 i += 1;
59 }
60 if cmd & 0b0010_0000 != 0 {
61 size |= u32::from(data[i]) << 8;
62 i += 1;
63 }
64 if cmd & 0b0100_0000 != 0 {
65 size |= u32::from(data[i]) << 16;
66 i += 1;
67 }
68 if size == 0 {
69 size = 0x10000; }
71 let ofs = ofs as usize;
72 std::io::Write::write(&mut target, &base[ofs..ofs + size as usize])
73 .map_err(|_e| apply::Error::DeltaCopyBaseSliceMismatch)?;
74 }
75 0 => return Err(apply::Error::UnsupportedCommandCode),
76 size => {
77 std::io::Write::write(&mut target, &data[i..i + *size as usize])
78 .map_err(|_e| apply::Error::DeltaCopyDataSliceMismatch)?;
79 i += *size as usize;
80 }
81 }
82 }
83 assert_eq!(i, data.len());
84 assert_eq!(target.len(), 0);
85
86 Ok(())
87}