Skip to main content

structured_asic/
media.rs

1//! Actual complete media-type bytes, without whole-member materialization.
2
3use 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/// MIME syntax and known `ASiC` essence, independent of application context.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Type {
19    /// A complete `application/vnd.etsi.asic-s+zip` value.
20    Simple,
21    /// A complete `application/vnd.etsi.asic-e+zip` value.
22    Extended,
23    /// A different complete MIME value. Original-container/data media types
24    /// can be permitted by EN319162-1 ยงยง4.3.3.1/4.4.3.1; this alone does not
25    /// establish that association or reject those normative alternatives.
26    Other,
27    /// Original bytes do not form a complete MIME value.
28    Malformed,
29}
30
31/// Original member whose complete bytes, extent and CRC were checked.
32pub struct Reading<D, G> {
33    member: MemberId<D, G>,
34    kind: Type,
35}
36impl<D: Copy, G: Copy> Reading<D, G> {
37    /// Exact original occurrence, not merely the filename `mimetype`.
38    #[must_use]
39    pub fn member(&self) -> MemberId<D, G> {
40        self.member
41    }
42    /// MIME syntax/essence facts from that actual complete input.
43    #[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    /// Streams the original full member through the existing incremental MIME
69    /// grammar. There is no joined media-type buffer, new parser or replay.
70    /// A malformed MIME reading still requires complete ZIP integrity.
71    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}