1use crate::container::XADES;
7use crate::properties::{self, Error, PropertyResult};
8use crate::xml::{Access, Name, Xml};
9use structured_asn1::memory::Work;
10
11mod meaning;
12pub use meaning::{
13 CheckError, CheckResult, Meaning, MeaningError, MeaningResult, check, check_value,
14};
15
16pub fn read_uri_syntax<X: crate::scalar::ScalarXml, W: Work>(
27 access: &Access<'_, X, W>,
28 parent: X::Id,
29) -> UriResult<X> {
30 use crate::reference::LexicalSource;
31 use crate::scalar::{Datatype, check};
32 read_with(access, parent, |node| {
33 check(access, node, LexicalSource::SimpleContent, Datatype::AnyUri)
34 .map_err(UriError::Scalar)
35 })
36}
37
38#[derive(Debug)]
40pub enum UriError<E, N> {
41 Structure(Error<E, N>),
43 Scalar(crate::scalar::Error<E, N>),
45}
46
47impl<E, N> From<Error<E, N>> for UriError<E, N> {
48 fn from(cause: Error<E, N>) -> Self {
49 Self::Structure(cause)
50 }
51}
52
53pub type UriResult<X> =
55 Result<Reading<<X as Xml>::Id>, UriError<<X as Xml>::Error, <X as Xml>::Id>>;
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub enum Qualifier {
60 Uri,
62 Urn,
64}
65
66#[derive(Debug)]
68pub struct Reading<N> {
69 pub identifier: N,
71 pub qualifier: Option<Qualifier>,
73 pub description: Option<N>,
75 pub documentation: Option<N>,
77}
78
79pub fn read<X: Xml, W: Work>(
88 access: &Access<'_, X, W>,
89 parent: X::Id,
90) -> PropertyResult<Reading<X::Id>, X> {
91 read_with(access, parent, |node| {
92 properties::simple_content(access, node)
93 })
94}
95
96fn read_with<X: Xml, W: Work, E: From<Error<X::Error, X::Id>>>(
100 access: &Access<'_, X, W>,
101 parent: X::Id,
102 mut uri: impl FnMut(X::Id) -> Result<(), E>,
103) -> Result<Reading<X::Id>, E> {
104 let mut fields = [None; 3];
105 let mut previous = 0;
106 for child in access.children(parent) {
107 let node = child.map_err(Error::Child)?;
108 let mut selected = None;
109 for (rank, local) in ["Identifier", "Description", "DocumentationReferences"]
110 .iter()
111 .enumerate()
112 {
113 if access
114 .has_name(
115 node,
116 Name {
117 namespace: XADES,
118 local,
119 },
120 )
121 .map_err(Error::Access)?
122 {
123 selected = Some(rank);
124 break;
125 }
126 }
127 let rank = selected.ok_or(Error::Unexpected { node })?;
128 if fields[rank].is_some() {
129 return Err(Error::Duplicate { node }.into());
130 }
131 if rank < previous {
132 return Err(Error::Order { node }.into());
133 }
134 fields[rank] = Some(node);
135 previous = rank;
136 if rank == 0 {
137 uri(node)?;
138 } else if rank == 1 {
139 properties::simple_content(access, node)?;
140 }
141 }
142 let identifier = fields[0].ok_or(Error::Missing {
143 parent,
144 local: "Identifier",
145 })?;
146 let qualifier = access
147 .attribute(
148 identifier,
149 Name {
150 namespace: "",
151 local: "Qualifier",
152 },
153 |value| {
154 let Some(value) = value else { return Ok(None) };
155 let refusal = |cause| Error::Resource {
156 node: identifier,
157 cause,
158 };
159 if access.equal(value, "OIDAsURI").map_err(refusal)? {
160 return Ok(Some(Qualifier::Uri));
161 }
162 if access.equal(value, "OIDAsURN").map_err(refusal)? {
163 return Ok(Some(Qualifier::Urn));
164 }
165 Err(Error::Unexpected { node: identifier })
166 },
167 )
168 .map_err(Error::Access)??;
169 documentation_with(access, fields[2], &mut uri)?;
170 Ok(Reading {
171 identifier,
172 qualifier,
173 description: fields[1],
174 documentation: fields[2],
175 })
176}
177
178fn documentation_with<X: Xml, W: Work, E: From<Error<X::Error, X::Id>>>(
181 access: &Access<'_, X, W>,
182 parent: Option<X::Id>,
183 mut uri: impl FnMut(X::Id) -> Result<(), E>,
184) -> Result<(), E> {
185 if let Some(parent) = parent {
186 let mut present = false;
187 for child in access.children(parent) {
188 let node = child.map_err(Error::Child)?;
189 if !access
190 .has_name(
191 node,
192 Name {
193 namespace: XADES,
194 local: "DocumentationReference",
195 },
196 )
197 .map_err(Error::Access)?
198 {
199 return Err(Error::Unexpected { node }.into());
200 }
201 uri(node)?;
202 present = true;
203 }
204 if !present {
205 return Err(Error::Missing {
206 parent,
207 local: "DocumentationReference",
208 }
209 .into());
210 }
211 }
212 Ok(())
213}