use crate::container::XADES;
use crate::properties::{self, Error, PropertyResult};
use crate::xml::{Access, Name, Xml};
use structured_asn1::memory::Work;
mod meaning;
pub use meaning::{
CheckError, CheckResult, Meaning, MeaningError, MeaningResult, check, check_value,
};
pub fn read_uri_syntax<X: crate::scalar::ScalarXml, W: Work>(
access: &Access<'_, X, W>,
parent: X::Id,
) -> UriResult<X> {
use crate::reference::LexicalSource;
use crate::scalar::{Datatype, check};
read_with(access, parent, |node| {
check(access, node, LexicalSource::SimpleContent, Datatype::AnyUri)
.map_err(UriError::Scalar)
})
}
#[derive(Debug)]
pub enum UriError<E, N> {
Structure(Error<E, N>),
Scalar(crate::scalar::Error<E, N>),
}
impl<E, N> From<Error<E, N>> for UriError<E, N> {
fn from(cause: Error<E, N>) -> Self {
Self::Structure(cause)
}
}
pub type UriResult<X> =
Result<Reading<<X as Xml>::Id>, UriError<<X as Xml>::Error, <X as Xml>::Id>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Qualifier {
Uri,
Urn,
}
#[derive(Debug)]
pub struct Reading<N> {
pub identifier: N,
pub qualifier: Option<Qualifier>,
pub description: Option<N>,
pub documentation: Option<N>,
}
pub fn read<X: Xml, W: Work>(
access: &Access<'_, X, W>,
parent: X::Id,
) -> PropertyResult<Reading<X::Id>, X> {
read_with(access, parent, |node| {
properties::simple_content(access, node)
})
}
fn read_with<X: Xml, W: Work, E: From<Error<X::Error, X::Id>>>(
access: &Access<'_, X, W>,
parent: X::Id,
mut uri: impl FnMut(X::Id) -> Result<(), E>,
) -> Result<Reading<X::Id>, E> {
let mut fields = [None; 3];
let mut previous = 0;
for child in access.children(parent) {
let node = child.map_err(Error::Child)?;
let mut selected = None;
for (rank, local) in ["Identifier", "Description", "DocumentationReferences"]
.iter()
.enumerate()
{
if access
.has_name(
node,
Name {
namespace: XADES,
local,
},
)
.map_err(Error::Access)?
{
selected = Some(rank);
break;
}
}
let rank = selected.ok_or(Error::Unexpected { node })?;
if fields[rank].is_some() {
return Err(Error::Duplicate { node }.into());
}
if rank < previous {
return Err(Error::Order { node }.into());
}
fields[rank] = Some(node);
previous = rank;
if rank == 0 {
uri(node)?;
} else if rank == 1 {
properties::simple_content(access, node)?;
}
}
let identifier = fields[0].ok_or(Error::Missing {
parent,
local: "Identifier",
})?;
let qualifier = access
.attribute(
identifier,
Name {
namespace: "",
local: "Qualifier",
},
|value| {
let Some(value) = value else { return Ok(None) };
let refusal = |cause| Error::Resource {
node: identifier,
cause,
};
if access.equal(value, "OIDAsURI").map_err(refusal)? {
return Ok(Some(Qualifier::Uri));
}
if access.equal(value, "OIDAsURN").map_err(refusal)? {
return Ok(Some(Qualifier::Urn));
}
Err(Error::Unexpected { node: identifier })
},
)
.map_err(Error::Access)??;
documentation_with(access, fields[2], &mut uri)?;
Ok(Reading {
identifier,
qualifier,
description: fields[1],
documentation: fields[2],
})
}
fn documentation_with<X: Xml, W: Work, E: From<Error<X::Error, X::Id>>>(
access: &Access<'_, X, W>,
parent: Option<X::Id>,
mut uri: impl FnMut(X::Id) -> Result<(), E>,
) -> Result<(), E> {
if let Some(parent) = parent {
let mut present = false;
for child in access.children(parent) {
let node = child.map_err(Error::Child)?;
if !access
.has_name(
node,
Name {
namespace: XADES,
local: "DocumentationReference",
},
)
.map_err(Error::Access)?
{
return Err(Error::Unexpected { node }.into());
}
uri(node)?;
present = true;
}
if !present {
return Err(Error::Missing {
parent,
local: "DocumentationReference",
}
.into());
}
}
Ok(())
}