structured_xades/counter/
walk.rs1use super::{Binding, Counter, CounterResult, Error, Original, bind, named};
4use crate::binding::{Selected, SignatureXml};
5use crate::container::{self, ContainerError, DS, Layout, XADES};
6use crate::properties;
7use crate::timestamp::{self, InputError};
8use crate::unsigned;
9use crate::xml::{Access, AccessError, Children, Xml};
10use structured_asn1::memory::{MemoryError, OwnedVec, Work};
11
12#[derive(Debug)]
15pub enum WalkError<E, VE, N> {
16 Access(AccessError<E, N>),
18 Container(ContainerError<E, N>),
20 Property(properties::Error<E, N>),
22 Counter(Error<E, N>),
24 Resource {
26 node: N,
28 cause: MemoryError,
30 },
31 Visitor(VE),
33}
34
35pub type WalkResult<T, X, VE> = Result<T, WalkError<<X as Xml>::Error, VE, <X as Xml>::Id>>;
37
38struct Frame<'a, 'xml, X: Xml, W: Work> {
39 layout: Layout<X>,
40 value: X::Id,
41 children: Children<'a, 'xml, X, W>,
42}
43
44pub fn walk<X: SignatureXml, W: Work, R, VE>(
70 access: &Access<'_, X, W>,
71 root: &Selected<X>,
72 mut visitor: impl FnMut(&Binding<X>, Option<&Layout<X>>) -> Result<R, VE>,
73) -> WalkResult<OwnedVec<R>, X, VE> {
74 let layout = root.containers();
75 if access.snapshot() != layout.snapshot() {
76 return Err(WalkError::Access(AccessError::Changed {
77 node: layout.signature(),
78 }));
79 }
80 let mut frames = access
81 .query(layout.signature(), |_, _, work| Ok(work.vector()))
82 .map_err(WalkError::Access)?;
83 let mut results = access
84 .query(layout.signature(), |_, _, work| Ok(work.vector()))
85 .map_err(WalkError::Access)?;
86 if let Some(frame) = frame(access, *layout)? {
87 frames
88 .try_push(frame)
89 .map_err(|cause| WalkError::Resource {
90 node: layout.signature(),
91 cause,
92 })?;
93 }
94 while let Some(current) = frames.last_mut() {
95 let Some(next) = current.children.next() else {
96 frames.pop();
97 continue;
98 };
99 let node =
100 next.map_err(|cause| WalkError::Counter(Error::Input(InputError::Child(cause))))?;
101 if !named(access, node, XADES, "CounterSignature").map_err(WalkError::Counter)? {
102 continue;
103 }
104 let original = member(access, current.layout.signature(), current.value, node)
105 .map_err(WalkError::Counter)?;
106 let checked = bind(access, original).map_err(WalkError::Counter)?;
107 let child = checked.original().child();
108 let nested = match container::locate(access, child) {
109 Ok(layout) => Some(layout),
110 Err(ContainerError::Missing {
113 parent,
114 local: "QualifyingProperties",
115 }) => {
116 if !access
117 .equal_id(parent, child)
118 .map_err(|cause| WalkError::Resource { node: child, cause })?
119 {
120 return Err(WalkError::Container(ContainerError::Missing {
121 parent,
122 local: "QualifyingProperties",
123 }));
124 }
125 None
126 }
127 Err(cause) => return Err(WalkError::Container(cause)),
128 };
129 let pending = nested
130 .map(|layout| frame(access, layout))
131 .transpose()?
132 .flatten();
133 let result = visitor(&checked, nested.as_ref()).map_err(WalkError::Visitor)?;
134 access
137 .query(child, |_, _, _| Ok(()))
138 .map_err(WalkError::Access)?;
139 results
140 .try_push(result)
141 .map_err(|cause| WalkError::Resource { node, cause })?;
142 if let Some(pending) = pending {
143 frames
144 .try_push(pending)
145 .map_err(|cause| WalkError::Resource { node: child, cause })?;
146 }
147 }
148 access
149 .query(layout.signature(), |_, _, _| Ok(()))
150 .map_err(WalkError::Access)?;
151 Ok(results.into_owned())
152}
153
154fn frame<'a, 'xml, X: Xml, W: Work, VE>(
155 access: &'a Access<'xml, X, W>,
156 layout: Layout<X>,
157) -> WalkResult<Option<Frame<'a, 'xml, X, W>>, X, VE> {
158 let [parent, _] =
159 unsigned::containers(access, layout.unsigned()).map_err(WalkError::Property)?;
160 let Some(parent) = parent else {
161 return Ok(None);
162 };
163 let value = timestamp::singleton(access, layout.signature(), DS, "SignatureValue")
164 .map_err(|cause| WalkError::Counter(Error::Input(cause)))?;
165 Ok(Some(Frame {
166 layout,
167 value,
168 children: access.children(parent),
169 }))
170}
171
172pub(super) fn member<X: Xml, W: Work>(
175 access: &Access<'_, X, W>,
176 parent: X::Id,
177 value: X::Id,
178 node: X::Id,
179) -> CounterResult<Original<X>, X> {
180 if !named(access, node, XADES, "CounterSignature")? {
181 return Err(Error::Input(InputError::Unexpected { node }));
182 }
183 let mut child = None;
184 for next in access.children(node) {
185 let next = next.map_err(|cause| Error::Input(InputError::Child(cause)))?;
186 if !named(access, next, DS, "Signature")? {
187 return Err(Error::Input(InputError::Unexpected { node: next }));
188 }
189 if child.is_some() {
190 return Err(Error::Input(InputError::Duplicate { node: next }));
191 }
192 child = Some(next);
193 }
194 let child = child.ok_or(Error::Input(InputError::Missing {
195 node,
196 local: "Signature",
197 }))?;
198 Ok(Counter {
199 snapshot: access.snapshot(),
200 parent,
201 value,
202 node,
203 child,
204 })
205}