use crate::{
error::{Error, resource},
zip::{Member, MemberId, ReadFailure},
};
use structured_asn1::{
memory::{MemoryError, Work},
range::RangeSource,
};
use structured_cms::{
mime::Essences,
stream::{AsyncSource, Receiver, Refused},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Type {
Simple,
Extended,
Other,
Malformed,
}
pub struct Reading<D, G> {
member: MemberId<D, G>,
kind: Type,
}
impl<D: Copy, G: Copy> Reading<D, G> {
#[must_use]
pub fn member(&self) -> MemberId<D, G> {
self.member
}
#[must_use]
pub fn kind(&self) -> Type {
self.kind
}
}
struct Inspect<'a, W: Work> {
syntax: Essences<'static, 2>,
work: &'a W,
refused: Option<MemoryError>,
}
impl<W: Work> Receiver for Inspect<'_, W> {
fn write(&mut self, bytes: &[u8]) -> Result<(), Refused> {
if self.refused.is_some() {
return Err(Refused);
}
if let Err(cause) = self.syntax.feed(bytes, self.work) {
self.refused = Some(cause);
return Err(Refused);
}
Ok(())
}
}
impl<S: RangeSource> Member<'_, '_, S> {
pub async fn read_media<W: Work>(
&self,
work: &W,
) -> Result<
Reading<S::Document, S::Generation>,
ReadFailure<S::Error, S::Document, S::Generation>,
> {
let mut source = self.source(work)?;
let execution = self.session().query(work);
let mut inspect = Inspect {
syntax: Essences::new([
("application", "vnd.etsi.asic-s+zip"),
("application", "vnd.etsi.asic-e+zip"),
]),
work: &execution,
refused: None,
};
let result = source.stream(&mut inspect, &execution).await;
if let Some(cause) = inspect.refused {
return Err(ReadFailure::Processing {
member: self.id(),
cause: resource(self.central_span(), cause),
});
}
result?;
self.archive()
.admit(&execution, self.central_span())
.map_err(|cause: Error<S::Error>| ReadFailure::Processing {
member: self.id(),
cause,
})?;
let kind = if !inspect.syntax.complete() {
Type::Malformed
} else if inspect.syntax.matches(0) == Some(true) {
Type::Simple
} else if inspect.syntax.matches(1) == Some(true) {
Type::Extended
} else {
Type::Other
};
Ok(Reading {
member: self.id(),
kind,
})
}
}