git_plumber/git/pack/
delta.rs1use std::fmt;
2
3#[derive(Debug, Clone)]
4pub enum DeltaInstruction {
5 Copy { offset: usize, size: usize },
6 Insert { data: Vec<u8> },
7}
8
9impl fmt::Display for DeltaInstruction {
10 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11 match self {
12 DeltaInstruction::Copy { offset, size } => {
13 write!(f, "Copy: offset={offset}, size={size}")
14 }
15 DeltaInstruction::Insert { data } => {
16 write!(f, "Insert: {} bytes", data.len())?;
17 if data.len() <= 100 {
18 write!(f, " (Data: {:?})", String::from_utf8_lossy(data))
19 } else {
20 write!(f, " (Data: {:?}...)", String::from_utf8_lossy(&data[..100]))
21 }
22 }
23 }
24 }
25}
26
27pub fn parse_delta_instructions(input: &[u8]) -> nom::IResult<&[u8], Vec<DeltaInstruction>> {
28 let mut instructions = Vec::new();
29 let mut i = 0;
30
31 while i < input.len() {
32 let first_byte = input[i];
33 i += 1;
34
35 if first_byte == 0 {
36 continue;
38 }
39
40 if first_byte & 0x80 != 0 {
41 let mut offset = 0;
43 let mut size = 0;
44 let mut shift = 0;
45
46 for bit in 0..4 {
48 if first_byte & (1 << bit) != 0 {
49 if i >= input.len() {
50 return Err(nom::Err::Incomplete(nom::Needed::new(1)));
51 }
52 offset |= (input[i] as usize) << shift;
53 i += 1;
54 }
55 shift += 8;
56 }
57
58 shift = 0;
60 for bit in 4..7 {
61 if first_byte & (1 << bit) != 0 {
62 if i >= input.len() {
63 return Err(nom::Err::Incomplete(nom::Needed::new(1)));
64 }
65 size |= (input[i] as usize) << shift;
66 i += 1;
67 }
68 shift += 8;
69 }
70
71 if size == 0 {
73 size = 0x10000;
74 }
75
76 instructions.push(DeltaInstruction::Copy { offset, size });
77 } else {
78 let size = first_byte as usize;
80 if size == 0 {
81 return Err(nom::Err::Error(nom::error::Error::new(
82 &input[i..],
83 nom::error::ErrorKind::Tag,
84 )));
85 }
86 if i + size > input.len() {
87 return Err(nom::Err::Incomplete(nom::Needed::new(size)));
88 }
89 let data = input[i..i + size].to_vec();
90 i += size;
91 instructions.push(DeltaInstruction::Insert { data });
92 }
93 }
94
95 Ok((&input[i..], instructions))
96}
97
98pub fn parse_delta_object(data: &[u8]) -> Vec<u8> {
99 let mut i = 0;
100 let mut _shift = 0;
101
102 loop {
104 if i >= data.len() {
105 return data.to_vec(); }
107 let byte = data[i];
108 i += 1;
109 if byte & 0x80 == 0 {
110 break;
111 }
112 _shift += 7;
113 }
114
115 _shift = 0;
117
118 loop {
120 if i >= data.len() {
121 return data.to_vec(); }
123 let byte = data[i];
124 i += 1;
125 if byte & 0x80 == 0 {
126 break;
127 }
128 _shift += 7;
129 }
130
131 data[i..].to_vec()
133}