use crate::document::{DocumentView, NodeIdentity, XmlDocumentError};
use structured_asn1::memory::{MemoryError, Work};
mod scalar;
pub use scalar::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BooleanAttribute {
Absent,
Value(bool),
Malformed,
}
#[derive(Debug, thiserror::Error)]
pub enum ScalarError {
#[error(transparent)]
Document(#[from] XmlDocumentError),
#[error("XML scalar owner is not an element")]
NotElement,
#[error("XML scalar resource failure: {0}")]
Resource(MemoryError),
}
pub(super) fn charge_bytes<W: Work>(work: &W, bytes: usize) -> Result<(), ScalarError> {
let bytes =
u64::try_from(bytes).map_err(|_| ScalarError::Resource(MemoryError::WorkExceeded))?;
work.charge_work(bytes).map_err(ScalarError::Resource)
}
pub fn boolean_attribute<W: Work>(
view: DocumentView<'_>,
owner: NodeIdentity,
namespace: Option<&str>,
local_name: &str,
work: &W,
) -> Result<BooleanAttribute, ScalarError> {
work.charge_work(1).map_err(ScalarError::Resource)?;
let node = view.resolve_node(owner)?;
if !node.is_element() {
return Err(ScalarError::NotElement);
}
for attribute in node.attributes() {
work.charge_work(1).map_err(ScalarError::Resource)?;
charge_bytes(work, attribute.name().len())?;
if attribute.name() != local_name {
continue;
}
if let Some(uri) = attribute.namespace() {
charge_bytes(work, uri.len())?;
}
if attribute.namespace() != namespace {
continue;
}
let value = attribute.value();
charge_bytes(work, value.len())?;
work.charge_work(5).map_err(ScalarError::Resource)?;
return Ok(match value.trim_matches([' ', '\t', '\r', '\n']) {
"true" | "1" => BooleanAttribute::Value(true),
"false" | "0" => BooleanAttribute::Value(false),
_ => BooleanAttribute::Malformed,
});
}
Ok(BooleanAttribute::Absent)
}