use oxml_core::OxmlError;
use quick_xml::XmlVersion;
use quick_xml::events::BytesStart;
pub const A_NS: &str = "http://schemas.openxmlformats.org/drawingml/2006/main";
pub const A_PREFIX: &str = "a";
pub const PIC_NS: &str = "http://schemas.openxmlformats.org/drawingml/2006/picture";
pub const PIC_PREFIX: &str = "pic";
pub(crate) fn reject_conflicting_a_prefix(element: &BytesStart<'_>) -> Result<(), OxmlError> {
for attribute in element.attributes() {
let attribute = attribute.map_err(OxmlError::from)?;
if attribute.key.as_ref() == b"xmlns:a" {
let value = attribute
.decoded_and_normalized_value(XmlVersion::Implicit1_0, element.decoder())
.map_err(OxmlError::from)?;
if value != A_NS {
return Err(OxmlError::InvalidValue(
"xmlns:a conflicts with the fixed DrawingML writer namespace".to_owned(),
));
}
}
}
Ok(())
}
pub(crate) fn property_namespace_scope(
element: &BytesStart<'_>,
inherited: &[(String, String)],
) -> Result<Vec<(String, String)>, OxmlError> {
let mut scope = inherited.to_vec();
if inherited.is_empty() {
scope.push(("a".to_owned(), A_NS.to_owned()));
let name = element.name();
let spelling = std::str::from_utf8(name.as_ref()).map_err(OxmlError::from)?;
let prefix = spelling.split_once(':').map_or("", |(prefix, _)| prefix);
if !scope.iter().any(|(name, _)| name == prefix) {
scope.push((prefix.to_owned(), A_NS.to_owned()));
}
}
for attribute in element.attributes() {
let attribute = attribute.map_err(OxmlError::from)?;
let key = attribute.key.as_ref();
let prefix = if key == b"xmlns" {
Some("")
} else if let Some(prefix) = key.strip_prefix(b"xmlns:") {
Some(std::str::from_utf8(prefix).map_err(OxmlError::from)?)
} else {
None
};
if let Some(prefix) = prefix {
let value = attribute
.decoded_and_normalized_value(XmlVersion::Implicit1_0, element.decoder())
.map_err(OxmlError::from)?
.into_owned();
if let Some((_, old)) = scope.iter_mut().find(|(name, _)| name == prefix) {
*old = value;
} else {
scope.push((prefix.to_owned(), value));
}
}
}
Ok(scope)
}
pub(crate) fn property_is_drawing(
element: &BytesStart<'_>,
inherited: &[(String, String)],
) -> Result<bool, OxmlError> {
let scope = property_namespace_scope(element, inherited)?;
let name = element.name();
let spelling = std::str::from_utf8(name.as_ref()).map_err(OxmlError::from)?;
let prefix = spelling.split_once(':').map_or("", |(prefix, _)| prefix);
Ok(scope
.iter()
.any(|(name, uri)| name == prefix && uri == A_NS))
}
pub(crate) fn property_reject_writer_conflicts(
scope: &[(String, String)],
) -> Result<(), OxmlError> {
if scope
.iter()
.any(|(prefix, uri)| prefix == "a" && uri != A_NS)
{
return Err(OxmlError::InvalidValue(
"unsupported typed property binding: in-scope a namespace conflicts with the fixed DrawingML writer".to_owned(),
));
}
Ok(())
}