1use crate::{
4 error::{Error, resource},
5 zip::{Member, MemberId, ReadFailure},
6};
7use structured_asn1::{
8 memory::{MemoryError, Work},
9 range::RangeSource,
10};
11use structured_cms::{
12 mime::Essences,
13 stream::{AsyncSource, Receiver, Refused},
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Type {
19 Simple,
21 Extended,
23 Other,
27 Malformed,
29}
30
31pub struct Reading<D, G> {
33 member: MemberId<D, G>,
34 kind: Type,
35}
36impl<D: Copy, G: Copy> Reading<D, G> {
37 #[must_use]
39 pub fn member(&self) -> MemberId<D, G> {
40 self.member
41 }
42 #[must_use]
44 pub fn kind(&self) -> Type {
45 self.kind
46 }
47}
48
49struct Inspect<'a, W: Work> {
50 syntax: Essences<'static, 2>,
51 work: &'a W,
52 refused: Option<MemoryError>,
53}
54impl<W: Work> Receiver for Inspect<'_, W> {
55 fn write(&mut self, bytes: &[u8]) -> Result<(), Refused> {
56 if self.refused.is_some() {
57 return Err(Refused);
58 }
59 if let Err(cause) = self.syntax.feed(bytes, self.work) {
60 self.refused = Some(cause);
61 return Err(Refused);
62 }
63 Ok(())
64 }
65}
66
67impl<S: RangeSource> Member<'_, '_, S> {
68 pub async fn read_media<W: Work>(
72 &self,
73 work: &W,
74 ) -> Result<
75 Reading<S::Document, S::Generation>,
76 ReadFailure<S::Error, S::Document, S::Generation>,
77 > {
78 let mut source = self.source(work)?;
79 let execution = self.session().query(work);
80 let mut inspect = Inspect {
81 syntax: Essences::new([
82 ("application", "vnd.etsi.asic-s+zip"),
83 ("application", "vnd.etsi.asic-e+zip"),
84 ]),
85 work: &execution,
86 refused: None,
87 };
88 let result = source.stream(&mut inspect, &execution).await;
89 if let Some(cause) = inspect.refused {
90 return Err(ReadFailure::Processing {
91 member: self.id(),
92 cause: resource(self.central_span(), cause),
93 });
94 }
95 result?;
96 self.archive()
97 .admit(&execution, self.central_span())
98 .map_err(|cause: Error<S::Error>| ReadFailure::Processing {
99 member: self.id(),
100 cause,
101 })?;
102 let kind = if !inspect.syntax.complete() {
103 Type::Malformed
104 } else if inspect.syntax.matches(0) == Some(true) {
105 Type::Simple
106 } else if inspect.syntax.matches(1) == Some(true) {
107 Type::Extended
108 } else {
109 Type::Other
110 };
111 Ok(Reading {
112 member: self.id(),
113 kind,
114 })
115 }
116}