1use super::encode::write_entry_header;
3use crate::{
4 Error, ObjectId, ObjectInfo, Repository, Result, io::SliceWriter, object::Hash,
5 zlib::adler::Adler32,
6};
7
8pub struct Encoder<'a> {
12 order: Option<&'a [usize]>,
13 count: usize,
14 next: usize,
15 object: Option<LooseEncoder>,
16 hash: Hash,
17 pending: [u8; 32],
18 position: usize,
19 length: usize,
20 checksum: Option<ObjectId>,
21}
22
23impl<'a> Encoder<'a> {
24 pub fn new(repository: &impl Repository, order: Option<&'a [usize]>) -> Result<Self> {
27 if let Some(order) = order {
28 super::encode::validate_order(repository, order)?;
29 }
30 let count = order.map_or(repository.object_count(), <[usize]>::len);
31 let count32 = u32::try_from(count).map_err(|_| Error::Unsupported)?;
32 let mut pending = [0; 32];
33 pending[..4].copy_from_slice(b"PACK");
34 pending[4..8].copy_from_slice(&2_u32.to_be_bytes());
35 pending[8..12].copy_from_slice(&count32.to_be_bytes());
36 Ok(Self {
37 order,
38 count,
39 next: 0,
40 object: None,
41 hash: repository.object_format().hash(),
42 pending,
43 position: 0,
44 length: 12,
45 checksum: None,
46 })
47 }
48
49 pub fn read(&mut self, repository: &impl Repository, output: &mut [u8]) -> Result<usize> {
54 loop {
55 if self.position < self.length {
56 let count = drain(&self.pending[..self.length], &mut self.position, output)?;
57 if self.checksum.is_none() {
58 self.hash.update(&output[..count]);
59 }
60 return Ok(count);
61 }
62 if self.checksum.is_some() {
63 return Ok(0);
64 }
65 if output.is_empty() {
66 return Err(Error::BufferTooSmall);
67 }
68 if let Some(object) = &mut self.object {
69 let count = object.read(repository, output)?;
70 if count != 0 {
71 self.hash.update(&output[..count]);
72 return Ok(count);
73 }
74 self.object = None;
75 self.next += 1;
76 }
77 self.next_entry(repository)?;
78 }
79 }
80
81 fn next_entry(&mut self, repository: &impl Repository) -> Result<()> {
82 if self.next == self.count {
83 let checksum = self.hash.clone().finish();
84 self.pending[..checksum.as_bytes().len()].copy_from_slice(checksum.as_bytes());
85 self.position = 0;
86 self.length = checksum.as_bytes().len();
87 self.checksum = Some(checksum);
88 return Ok(());
89 }
90 let index = self.order.map_or(self.next, |order| order[self.next]);
91 let info = repository.object_info(index)?;
92 let mut header = SliceWriter::new(&mut self.pending);
93 write_entry_header(info, &mut header)?;
94 self.length = header.len();
95 self.position = 0;
96 self.object = Some(LooseEncoder::from_info(index, info, false)?);
97 Ok(())
98 }
99
100 pub fn selection(&self) -> Option<&'a [usize]> {
103 self.order
104 }
105
106 pub fn checksum(&self) -> Option<ObjectId> {
108 self.checksum.filter(|_| self.position == self.length)
109 }
110}
111
112pub struct LooseEncoder {
115 index: usize,
116 size: u64,
117 offset: u64,
118 block: u16,
119 adler: Adler32,
120 prefix: [u8; 32],
121 prefix_length: usize,
122 pending: [u8; 64],
123 position: usize,
124 length: usize,
125 phase: Phase,
126}
127
128enum Phase {
129 Prefix,
130 Block,
131 Body,
132 End,
133 Done,
134}
135
136impl LooseEncoder {
137 pub fn new(repository: &impl Repository, index: usize) -> Result<Self> {
138 Self::from_info(index, repository.object_info(index)?, true)
139 }
140
141 pub(super) fn from_info(index: usize, info: ObjectInfo, loose: bool) -> Result<Self> {
142 let mut prefix = [0; 32];
143 let prefix_length = if loose {
144 info.header(&mut prefix)?.len()
145 } else {
146 0
147 };
148 let mut pending = [0; 64];
149 pending[..2].copy_from_slice(&[0x78, 0x01]);
150 Ok(Self {
151 index,
152 size: info.size,
153 offset: 0,
154 block: 0,
155 adler: Adler32::new(),
156 prefix,
157 prefix_length,
158 pending,
159 position: 0,
160 length: 2,
161 phase: Phase::Prefix,
162 })
163 }
164
165 pub fn read(&mut self, repository: &impl Repository, output: &mut [u8]) -> Result<usize> {
166 loop {
167 if self.position < self.length {
168 return drain(&self.pending[..self.length], &mut self.position, output);
169 }
170 if matches!(self.phase, Phase::Done) {
171 return Ok(0);
172 }
173 if output.is_empty() {
174 return Err(Error::BufferTooSmall);
175 }
176 self.position = 0;
177 self.length = 0;
178 if let Some(count) = self.step(repository, output)? {
179 return Ok(count);
180 }
181 }
182 }
183
184 fn step(&mut self, repository: &impl Repository, output: &mut [u8]) -> Result<Option<usize>> {
185 match self.phase {
186 Phase::Prefix => self.start_prefix(),
187 Phase::Block => self.start_block(),
188 Phase::Body => return self.read_body(repository, output).map(Some),
189 Phase::End => self.end(),
190 Phase::Done => unreachable!(),
191 }
192 Ok(None)
193 }
194
195 fn start_prefix(&mut self) {
196 self.phase = Phase::Block;
197 if self.prefix_length == 0 {
198 return;
199 }
200 self.block_header(self.prefix_length as u16);
201 self.pending[5..5 + self.prefix_length].copy_from_slice(&self.prefix[..self.prefix_length]);
202 self.length += self.prefix_length;
203 self.adler.update(&self.prefix[..self.prefix_length]);
204 }
205
206 fn start_block(&mut self) {
207 if self.offset == self.size {
208 self.phase = Phase::End;
209 return;
210 }
211 self.block = (self.size - self.offset).min(u64::from(u16::MAX)) as u16;
212 self.block_header(self.block);
213 self.phase = Phase::Body;
214 }
215
216 fn read_body(&mut self, repository: &impl Repository, output: &mut [u8]) -> Result<usize> {
217 let capacity = usize::from(self.block).min(output.len());
218 let count = repository.read_object(self.index, self.offset, &mut output[..capacity])?;
219 if count == 0 || count > capacity {
220 return Err(Error::InvalidObject);
221 }
222 self.offset += count as u64;
223 self.block -= count as u16;
224 self.adler.update(&output[..count]);
225 if self.block == 0 {
226 self.phase = Phase::Block;
227 }
228 Ok(count)
229 }
230
231 fn end(&mut self) {
232 self.pending[..5].copy_from_slice(&[1, 0, 0, 0xff, 0xff]);
233 self.pending[5..9].copy_from_slice(&self.adler.value().to_be_bytes());
234 self.length = 9;
235 self.phase = Phase::Done;
236 }
237
238 fn block_header(&mut self, length: u16) {
239 self.pending[0] = 0;
240 self.pending[1..3].copy_from_slice(&length.to_le_bytes());
241 self.pending[3..5].copy_from_slice(&(!length).to_le_bytes());
242 self.length = 5;
243 }
244}
245
246pub(crate) fn drain(bytes: &[u8], position: &mut usize, output: &mut [u8]) -> Result<usize> {
247 if output.is_empty() {
248 return Err(Error::BufferTooSmall);
249 }
250 let count = output.len().min(bytes.len() - *position);
251 output[..count].copy_from_slice(&bytes[*position..*position + count]);
252 *position += count;
253 Ok(count)
254}