1use structured_asn1::memory::{MemoryError, OwnedVec, Work};
4use structured_xades::{
5 attributes::AttributeXml,
6 reference::VisitError,
7 scalar::ScalarXml,
8 xml::{Access, AccessError, Name, Node, Snapshot, Xml},
9};
10
11mod fields;
12
13pub const NAMESPACE: &str = "http://uri.etsi.org/02918/v1.2.1#";
15pub(crate) const DS: &str = "http://www.w3.org/2000/09/xmldsig#";
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Slot<N> {
20 Absent,
22 One(N),
24 Ambiguous,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum Boolean {
31 Absent,
33 Value(bool),
35 Malformed,
37}
38
39#[derive(Debug, Clone, Copy)]
41pub struct Object<N> {
42 pub node: N,
44 pub method: Slot<N>,
46 pub value: Slot<N>,
48 pub rootfile: Boolean,
50}
51
52#[derive(Debug, Clone, Copy)]
54pub struct Extension<N> {
55 pub owner: N,
57 pub node: N,
59 pub critical: Boolean,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum FaultKind {
66 Text,
68 Unexpected,
70 Missing,
72 Duplicate,
74 Order,
76 Scalar,
78 InstanceUnassessed,
80}
81
82#[derive(Debug, Clone, Copy)]
84pub struct Fault<N> {
85 pub node: N,
87 pub kind: FaultKind,
89}
90
91#[derive(Debug)]
93pub enum Error<E, N> {
94 Access(AccessError<E, N>),
96 Attributes(AccessError<VisitError<E, MemoryError>, N>),
98 Resource {
100 node: N,
102 cause: MemoryError,
104 },
105 Root(N),
107}
108
109type ResultOf<T, X> = Result<T, Error<<X as Xml>::Error, <X as Xml>::Id>>;
110pub type InspectionResult<X> =
112 ResultOf<Reading<<X as Xml>::Id, <X as Xml>::Document, <X as Xml>::Generation>, X>;
113
114pub struct Reading<N, D, G> {
117 snapshot: Snapshot<D, G>,
118 root: N,
119 signatures: OwnedVec<N>,
120 objects: OwnedVec<Object<N>>,
121 extensions: OwnedVec<Extension<N>>,
122 faults: OwnedVec<Fault<N>>,
123}
124
125pub(crate) struct Builder<N, W: Work> {
126 signatures: OwnedVec<N, W>,
127 objects: OwnedVec<Object<N>, W>,
128 extensions: OwnedVec<Extension<N>, W>,
129 faults: OwnedVec<Fault<N>, W>,
130}
131
132impl<N: Copy, W: Work> Builder<N, W> {
133 fn fault<E>(&mut self, node: N, kind: FaultKind) -> Result<(), Error<E, N>> {
134 self.faults
135 .try_push(Fault { node, kind })
136 .map_err(|cause| Error::Resource { node, cause })
137 }
138}
139
140impl<N: Copy, D: Copy + Eq, G: Copy + Eq> Reading<N, D, G> {
141 #[must_use]
143 pub fn snapshot(&self) -> Snapshot<D, G> {
144 self.snapshot
145 }
146 #[must_use]
148 pub fn root(&self) -> N {
149 self.root
150 }
151 #[must_use]
153 pub fn objects(&self) -> &[Object<N>] {
154 &self.objects
155 }
156 #[must_use]
158 pub fn signatures(&self) -> &[N] {
159 &self.signatures
160 }
161 #[must_use]
163 pub fn extensions(&self) -> &[Extension<N>] {
164 &self.extensions
165 }
166 #[must_use]
168 pub fn faults(&self) -> &[Fault<N>] {
169 &self.faults
170 }
171}
172
173pub fn inspect<X: AttributeXml + ScalarXml, W: Work>(
177 access: &Access<'_, X, W>,
178 root: X::Id,
179) -> InspectionResult<X> {
180 if !access
181 .has_name(root, name("ASiCManifest"))
182 .map_err(Error::Access)?
183 {
184 return Err(Error::Root(root));
185 }
186 let work = access.execution();
187 let mut output = Builder {
188 signatures: work.vector(),
189 objects: work.vector(),
190 extensions: work.vector(),
191 faults: work.vector(),
192 };
193 fields::attributes(access, root, &[], &mut output)?;
194 let mut stage = 0;
195 let mut extension = false;
196 walk(access, root, |node, element| {
197 if !element {
198 return output.fault(node, FaultKind::Text);
199 }
200 if access
201 .has_name(node, name("SigReference"))
202 .map_err(Error::Access)?
203 {
204 if stage != 0 {
205 output.fault(node, FaultKind::Order)?;
206 }
207 if !output.signatures.is_empty() {
208 output.fault(node, FaultKind::Duplicate)?;
209 }
210 fields::attributes(access, node, &["URI", "MimeType"], &mut output)?;
211 fields::uri(access, node, &mut output)?;
212 fields::empty(access, node, &mut output)?;
213 output
214 .signatures
215 .try_push(node)
216 .map_err(|cause| Error::Resource { node, cause })?;
217 } else if access
218 .has_name(node, name("DataObjectReference"))
219 .map_err(Error::Access)?
220 {
221 if stage > 1 || output.signatures.is_empty() {
222 output.fault(node, FaultKind::Order)?;
223 }
224 stage = stage.max(1);
225 let value = fields::object(access, node, &mut output)?;
226 output
227 .objects
228 .try_push(value)
229 .map_err(|cause| Error::Resource { node, cause })?;
230 } else if access
231 .has_name(node, name("ASiCManifestExtensions"))
232 .map_err(Error::Access)?
233 {
234 if extension {
235 output.fault(node, FaultKind::Duplicate)?;
236 }
237 if output.objects.is_empty() {
238 output.fault(node, FaultKind::Order)?;
239 }
240 stage = 2;
241 extension = true;
242 fields::extensions(access, root, node, &mut output)?;
243 } else {
244 output.fault(node, FaultKind::Unexpected)?;
245 }
246 Ok(())
247 })?;
248 if output.signatures.is_empty() || output.objects.is_empty() {
249 output.fault(root, FaultKind::Missing)?;
250 }
251 Ok(Reading {
252 snapshot: access.snapshot(),
253 root,
254 signatures: output.signatures.into_owned(),
255 objects: output.objects.into_owned(),
256 extensions: output.extensions.into_owned(),
257 faults: output.faults.into_owned(),
258 })
259}
260
261fn name(local: &'static str) -> Name<'static> {
262 Name {
263 namespace: NAMESPACE,
264 local,
265 }
266}
267
268fn walk<X: Xml, W: Work>(
269 access: &Access<'_, X, W>,
270 parent: X::Id,
271 mut visit: impl FnMut(X::Id, bool) -> ResultOf<(), X>,
272) -> ResultOf<(), X> {
273 let mut child = access.first_child(parent).map_err(Error::Access)?;
274 while let Some(node) = child {
275 let class = access
276 .inspect(node, |read| match read {
277 Node::Element(_) => Ok(Some(true)),
278 Node::Text(text) => {
279 access.execution().charge_work(text.len() as u64)?;
280 for byte in text.bytes() {
281 if !matches!(byte, b' ' | b'\r' | b'\n' | b'\t') {
282 return Ok(Some(false));
283 }
284 }
285 Ok(None)
286 }
287 Node::Other => Ok(None),
288 })
289 .map_err(Error::Access)?
290 .map_err(|cause| Error::Resource { node, cause })?;
291 if let Some(element) = class {
292 visit(node, element)?;
293 }
294 child = access.next_sibling(parent, node).map_err(Error::Access)?;
295 }
296 Ok(())
297}