1use super::{DecodeStatus, EntryDecoder};
3use crate::{
4 Error, ObjectFormat, Result,
5 zlib::{InflateLimits, WINDOW_SIZE},
6};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct ByteRange {
10 pub offset: u64,
11 pub length: u64,
12}
13
14#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub enum EntryRangeStatus {
16 Continue,
18 NeedInput,
19 NeedOutput,
20 Finished,
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct EntryRangeProgress {
25 pub consumed: usize,
26 pub written: usize,
27 pub status: EntryRangeStatus,
28}
29
30pub struct EntryRangeDecoder<'window, 'scratch> {
42 decoder: EntryDecoder<'window>,
43 scratch: &'scratch mut [u8],
44 range: ByteRange,
45 end: u64,
46 inflated: u64,
47 emitted: u64,
48 pending: usize,
49 pending_end: usize,
50 header_seen: bool,
51 finished: bool,
52 failure: Option<Error>,
53}
54
55impl<'window, 'scratch> EntryRangeDecoder<'window, 'scratch> {
56 pub fn new(
57 format: ObjectFormat,
58 entry_offset: u64,
59 window: &'window mut [u8; WINDOW_SIZE],
60 max_entry_bytes: u64,
61 inflate: InflateLimits,
62 range: ByteRange,
63 scratch: &'scratch mut [u8],
64 ) -> Result<Self> {
65 let end = range
66 .offset
67 .checked_add(range.length)
68 .ok_or(Error::InvalidObject)?;
69 if scratch.is_empty() && range.length != 0 {
70 return Err(Error::BufferTooSmall);
71 }
72 Ok(Self {
73 decoder: EntryDecoder::new(format, entry_offset, window, max_entry_bytes, inflate)?,
74 scratch,
75 range,
76 end,
77 inflated: 0,
78 emitted: 0,
79 pending: 0,
80 pending_end: 0,
81 header_seen: false,
82 finished: false,
83 failure: None,
84 })
85 }
86
87 pub fn wire_position(&self) -> u64 {
88 self.decoder.position()
89 }
90 pub fn inflated_position(&self) -> u64 {
91 self.inflated
92 }
93 pub fn position(&self) -> u64 {
94 self.emitted
95 }
96
97 pub fn update(
100 &mut self,
101 input: &[u8],
102 output: &mut [u8],
103 end_of_input: bool,
104 ) -> Result<EntryRangeProgress> {
105 let result = self.advance(input, output, end_of_input);
106 if let Err(error) = result {
107 self.failure = Some(error);
108 }
109 result
110 }
111
112 pub fn finish(&self) -> Result<()> {
113 if let Some(error) = self.failure {
114 return Err(error);
115 }
116 if self.finished {
117 Ok(())
118 } else {
119 Err(Error::CorruptPack)
120 }
121 }
122
123 fn advance(
124 &mut self,
125 input: &[u8],
126 output: &mut [u8],
127 eof: bool,
128 ) -> Result<EntryRangeProgress> {
129 if let Some(error) = self.failure {
130 return Err(error);
131 }
132 if self.finished {
133 return Ok(EntryRangeProgress {
134 consumed: 0,
135 written: 0,
136 status: EntryRangeStatus::Finished,
137 });
138 }
139 if self.pending < self.pending_end {
140 return Ok(self.drain(0, output));
141 }
142 if output.is_empty() && self.range.length != 0 {
144 return Ok(EntryRangeProgress {
145 consumed: 0,
146 written: 0,
147 status: EntryRangeStatus::NeedOutput,
148 });
149 }
150 let progress = self.decoder.update(input, self.scratch, eof)?;
151 if let DecodeStatus::EntryStart(header) = progress.status {
152 if self.end > header.size {
153 return Err(Error::InvalidObject);
154 }
155 self.header_seen = true;
156 if self.range.length == 0 {
157 self.finished = true;
158 }
159 }
160 let before = self.inflated;
161 self.inflated += progress.written as u64;
162 let first = before.max(self.range.offset);
163 let last = self.inflated.min(self.end);
164 if first < last {
165 self.pending = (first - before) as usize;
166 self.pending_end = (last - before) as usize;
167 return Ok(self.drain(progress.consumed, output));
168 }
169 let status = if self.finished {
170 EntryRangeStatus::Finished
171 } else {
172 match progress.status {
173 DecodeStatus::NeedInput => EntryRangeStatus::NeedInput,
174 DecodeStatus::EntryEnd { .. } => return Err(Error::CorruptPack),
175 _ => EntryRangeStatus::Continue,
176 }
177 };
178 Ok(EntryRangeProgress {
179 consumed: progress.consumed,
180 written: 0,
181 status,
182 })
183 }
184
185 fn drain(&mut self, consumed: usize, output: &mut [u8]) -> EntryRangeProgress {
186 let written = (self.pending_end - self.pending).min(output.len());
187 output[..written].copy_from_slice(&self.scratch[self.pending..self.pending + written]);
188 self.pending += written;
189 self.emitted += written as u64;
190 self.finished = self.header_seen && self.emitted == self.range.length;
191 let status = if self.finished {
192 EntryRangeStatus::Finished
193 } else if self.pending < self.pending_end {
194 EntryRangeStatus::NeedOutput
195 } else {
196 EntryRangeStatus::Continue
197 };
198 EntryRangeProgress {
199 consumed,
200 written,
201 status,
202 }
203 }
204}