1use crate::{
4 Session,
5 error::{Error, resource},
6};
7use structured_asn1::{
8 Span,
9 memory::{OwnedVec, Work},
10 range::{RangeSource, Stamp, Window},
11};
12
13mod directory;
14mod framing;
15mod stream;
16pub use stream::{Acquisition, Integrity, ReadFailure, Source};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub struct MemberId<D, G> {
21 stamp: Stamp<D, G>,
22 ordinal: usize,
23}
24impl<D: Copy, G: Copy> MemberId<D, G> {
25 #[must_use]
27 pub fn ordinal(&self) -> usize {
28 self.ordinal
29 }
30 #[must_use]
32 pub fn stamp(&self) -> Stamp<D, G> {
33 self.stamp
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum FaultKind {
40 Utf8,
42 Name,
44 DuplicateName,
46 LocalMismatch,
48 Descriptor,
50 Overlap,
52 LocalBounds,
54 StoredLength,
56 Encrypted,
58 Compression,
60 IsoProfile,
62 Zip64,
64 UnicodeName,
66 DirectorySignature,
68}
69
70#[derive(Debug, Clone, Copy)]
72pub struct Fault {
73 pub member: Option<usize>,
75 pub range: Span,
77 pub kind: FaultKind,
79}
80
81#[derive(Clone, Copy)]
82struct Bytes {
83 start: usize,
84 length: usize,
85}
86impl Bytes {
87 fn get(self, values: &[u8]) -> &[u8] {
88 &values[self.start..self.start + self.length]
89 }
90}
91
92struct Entry {
93 central: Span,
94 name_span: Span,
95 extra: Span,
96 comment: Span,
97 name: Bytes,
98 needed: u16,
99 flags: u16,
100 method: u16,
101 crc: u32,
102 compressed: u64,
103 decoded: u64,
104 local: u64,
105 local_extra: Option<Span>,
106 data: Option<Span>,
107 enclosure: Option<Span>,
108 zip64: bool,
109 readable: bool,
110 disk: u32,
111 unicode: Option<Span>,
112 overlap: bool,
113}
114
115pub struct Archive<'s, S: RangeSource> {
118 source: &'s S,
119 session: &'s Session,
120 stamp: Stamp<S::Document, S::Generation>,
121 directory: Span,
122 comment: Span,
123 entries: OwnedVec<Entry>,
124 names: OwnedVec<u8>,
125 order: OwnedVec<usize>,
126 faults: OwnedVec<Fault>,
127}
128
129pub struct Member<'view, 'source, S: RangeSource> {
131 archive: &'view Archive<'source, S>,
132 ordinal: usize,
133}
134
135impl<'s, S: RangeSource> Archive<'s, S> {
136 pub(crate) fn session(&self) -> &'s Session {
137 self.session
138 }
139 pub async fn read<W: Work>(
142 source: &'s S,
143 session: &'s Session,
144 work: &W,
145 ) -> Result<Self, Error<S::Error>> {
146 directory::read(source, session, work).await
147 }
148 #[must_use]
150 pub fn stamp(&self) -> Stamp<S::Document, S::Generation> {
151 self.stamp
152 }
153 pub(crate) fn unchanged(&self) -> bool {
154 self.source.stamp() == self.stamp
155 }
156 #[must_use]
158 pub fn len(&self) -> usize {
159 self.entries.len()
160 }
161 #[must_use]
163 pub fn is_empty(&self) -> bool {
164 self.entries.is_empty()
165 }
166 #[must_use]
168 pub fn comment_span(&self) -> Span {
169 self.comment
170 }
171 #[must_use]
173 pub fn directory_span(&self) -> Span {
174 self.directory
175 }
176
177 pub(crate) fn admit<W: Work>(&self, work: &W, range: Span) -> Result<(), Error<S::Error>> {
178 self.session
179 .query(work)
180 .charge_work(1)
181 .map_err(|cause| resource(range, cause))?;
182 if self.source.stamp() != self.stamp {
183 return Err(structured_asn1::range::InputError::Changed { range }.into());
184 }
185 Ok(())
186 }
187
188 pub fn member<W: Work>(
191 &self,
192 ordinal: usize,
193 work: &W,
194 ) -> Result<Option<Member<'_, 's, S>>, Error<S::Error>> {
195 self.admit(work, self.directory)?;
196 if ordinal >= self.entries.len() {
197 return Ok(None);
198 }
199 Ok(Some(Member {
200 archive: self,
201 ordinal,
202 }))
203 }
204 pub fn original<W: Work>(
206 &self,
207 id: MemberId<S::Document, S::Generation>,
208 work: &W,
209 ) -> Result<Member<'_, 's, S>, Error<S::Error>> {
210 self.admit(work, self.directory)?;
211 if id.stamp != self.stamp || id.ordinal >= self.entries.len() {
212 return Err(Error::Foreign {
213 range: self.directory,
214 });
215 }
216 Ok(Member {
217 archive: self,
218 ordinal: id.ordinal,
219 })
220 }
221 pub fn faults<'v, 'q, W: Work>(
224 &'v self,
225 work: &'q W,
226 ) -> crate::error::SourceResult<
227 impl Iterator<Item = Result<Fault, Error<S::Error>>> + use<'v, 'q, 's, S, W>,
228 S,
229 > {
230 self.admit(work, self.directory)?;
231 let mut at = 0;
232 let mut refused = false;
233 Ok(core::iter::from_fn(move || {
234 if refused || at == self.faults.len() {
235 return None;
236 }
237 if let Err(cause) = self.admit(work, self.directory) {
238 refused = true;
239 return Some(Err(cause));
240 }
241 let value = self.faults[at];
242 at += 1;
243 Some(Ok(value))
244 }))
245 }
246
247 pub fn find<W: Work>(
250 &self,
251 name: &[u8],
252 work: &W,
253 ) -> Result<Names<'_, 's, S>, Error<S::Error>> {
254 self.admit(work, self.directory)?;
255 let execution = self.session.query(work);
256 let mut lo = 0;
257 let mut hi = self.order.len();
258 while lo < hi {
259 let mid = lo + (hi - lo) / 2;
260 let other = self.entries[self.order[mid]].name.get(&self.names);
261 execution
262 .charge_work(other.len().min(name.len()) as u64 + 1)
263 .map_err(|cause| resource(self.directory, cause))?;
264 if other < name {
265 lo = mid + 1;
266 } else {
267 hi = mid;
268 }
269 }
270 let first = lo;
271 hi = self.order.len();
272 while lo < hi {
273 let mid = lo + (hi - lo) / 2;
274 let other = self.entries[self.order[mid]].name.get(&self.names);
275 execution
276 .charge_work(other.len().min(name.len()) as u64 + 1)
277 .map_err(|cause| resource(self.directory, cause))?;
278 if other <= name {
279 lo = mid + 1;
280 } else {
281 hi = mid;
282 }
283 }
284 Ok(Names {
285 archive: self,
286 first,
287 end: lo,
288 })
289 }
290
291 fn window<'q, W: Work>(
292 &'q self,
293 work: &'q W,
294 bounds: Span,
295 ) -> Result<Window<'q, S>, Error<S::Error>> {
296 Ok(Window::new(
297 self.source,
298 self.stamp,
299 bounds,
300 self.session.query(work),
301 )?)
302 }
303}
304
305pub struct Names<'view, 'source, S: RangeSource> {
307 archive: &'view Archive<'source, S>,
308 first: usize,
309 end: usize,
310}
311impl<'v, 's, S: RangeSource> Names<'v, 's, S> {
312 #[must_use]
314 pub fn len(&self) -> usize {
315 self.end - self.first
316 }
317 #[must_use]
319 pub fn is_empty(&self) -> bool {
320 self.first == self.end
321 }
322 pub fn member<W: Work>(
324 &self,
325 ordinal: usize,
326 work: &W,
327 ) -> Result<Option<Member<'v, 's, S>>, Error<S::Error>> {
328 self.archive.admit(work, self.archive.directory)?;
329 if ordinal >= self.len() {
330 return Ok(None);
331 }
332 Ok(Some(Member {
333 archive: self.archive,
334 ordinal: self.archive.order[self.first + ordinal],
335 }))
336 }
337}
338
339impl<S: RangeSource> Member<'_, '_, S> {
340 fn entry(&self) -> &Entry {
341 &self.archive.entries[self.ordinal]
342 }
343 #[must_use]
345 pub fn id(&self) -> MemberId<S::Document, S::Generation> {
346 MemberId {
347 stamp: self.archive.stamp,
348 ordinal: self.ordinal,
349 }
350 }
351 #[must_use]
353 pub fn name(&self) -> &[u8] {
354 self.entry().name.get(&self.archive.names)
355 }
356 #[must_use]
358 pub fn central_span(&self) -> Span {
359 self.entry().central
360 }
361 #[must_use]
363 pub fn name_span(&self) -> Span {
364 self.entry().name_span
365 }
366 #[must_use]
368 pub fn method(&self) -> u16 {
369 self.entry().method
370 }
371 #[must_use]
373 pub fn flags(&self) -> u16 {
374 self.entry().flags
375 }
376 #[must_use]
378 pub fn version_needed(&self) -> u16 {
379 self.entry().needed
380 }
381 #[must_use]
383 pub fn data_span(&self) -> Option<Span> {
384 self.entry().data
385 }
386 #[must_use]
388 pub fn local_span(&self) -> Option<Span> {
389 self.entry().enclosure
390 }
391 #[must_use]
393 pub fn local_extra_span(&self) -> Option<Span> {
394 self.entry().local_extra
395 }
396 #[must_use]
398 pub fn decoded_length(&self) -> u64 {
399 self.entry().decoded
400 }
401}
402
403impl<'v, 's, S: RangeSource> Member<'v, 's, S> {
404 pub(crate) fn archive(&self) -> &'v Archive<'s, S> {
405 self.archive
406 }
407 pub(crate) fn session(&self) -> &'s Session {
408 self.archive.session
409 }
410}