mod escape;
pub use escape::{write_xml_escaped, xml_escape, xml_escape_char};
use std::borrow::Cow;
use std::fmt;
use quick_xml::events::{BytesStart, Event};
use quick_xml::Reader;
use crate::error::{PptxError, PptxResult};
pub trait WriteXml {
fn write_xml<W: fmt::Write>(&self, w: &mut W) -> fmt::Result;
fn to_xml_string(&self) -> String {
let mut s = String::new();
self.write_xml(&mut s)
.unwrap_or_else(|_| unreachable!("fmt::Write for String is infallible"));
s
}
}
#[inline]
pub fn local_name(name: &[u8]) -> &[u8] {
name.iter()
.position(|&b| b == b':')
.map_or(name, |pos| &name[pos + 1..])
}
#[inline]
pub fn local_name_str(name: &[u8]) -> &str {
std::str::from_utf8(local_name(name)).unwrap_or("")
}
#[inline]
pub fn local_name_owned(name: &[u8]) -> String {
let ln = local_name(name);
String::from_utf8_lossy(ln).into_owned()
}
#[inline]
pub fn attr_value<'a>(e: &'a BytesStart<'_>, key: &[u8]) -> PptxResult<Option<Cow<'a, str>>> {
for attr_result in e.attributes() {
let attr = attr_result.map_err(PptxError::XmlAttr)?;
let k = attr.key.as_ref();
if k == key || local_name(k) == key {
let value = match attr.value {
Cow::Borrowed(bytes) => Some(Cow::Borrowed(
std::str::from_utf8(bytes).map_err(PptxError::Utf8Str)?,
)),
Cow::Owned(vec) => {
Some(Cow::Owned(String::from_utf8(vec).map_err(PptxError::Utf8)?))
}
};
return Ok(value);
}
}
Ok(None)
}
#[inline]
pub fn attr_value_ns<'a>(
e: &'a BytesStart<'_>,
local_key: &[u8],
) -> PptxResult<Option<Cow<'a, str>>> {
for attr_result in e.attributes() {
let attr = attr_result.map_err(PptxError::XmlAttr)?;
if local_name(attr.key.as_ref()) == local_key {
let value = match attr.value {
Cow::Borrowed(bytes) => Some(Cow::Borrowed(
std::str::from_utf8(bytes).map_err(PptxError::Utf8Str)?,
)),
Cow::Owned(vec) => {
Some(Cow::Owned(String::from_utf8(vec).map_err(PptxError::Utf8)?))
}
};
return Ok(value);
}
}
Ok(None)
}
#[inline]
pub fn read_inner_xml(
reader: &mut Reader<&[u8]>,
end_tag: &str,
) -> Result<Vec<u8>, quick_xml::Error> {
let mut inner = Vec::new();
let mut buf = Vec::new();
let mut depth = 1u32;
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => {
depth += 1;
inner.extend_from_slice(b"<");
inner.extend_from_slice(e.name().as_ref());
for attr_result in e.attributes() {
let attr = attr_result?;
inner.extend_from_slice(b" ");
inner.extend_from_slice(attr.key.as_ref());
inner.extend_from_slice(b"=\"");
inner.extend_from_slice(&attr.value);
inner.extend_from_slice(b"\"");
}
inner.extend_from_slice(b">");
}
Ok(Event::Empty(ref e)) => {
inner.extend_from_slice(b"<");
inner.extend_from_slice(e.name().as_ref());
for attr_result in e.attributes() {
let attr = attr_result?;
inner.extend_from_slice(b" ");
inner.extend_from_slice(attr.key.as_ref());
inner.extend_from_slice(b"=\"");
inner.extend_from_slice(&attr.value);
inner.extend_from_slice(b"\"");
}
inner.extend_from_slice(b"/>");
}
Ok(Event::End(ref e)) => {
depth -= 1;
if depth == 0 {
let qn = e.name();
let local = local_name_str(qn.as_ref());
if local == end_tag {
break;
}
}
inner.extend_from_slice(b"</");
inner.extend_from_slice(e.name().as_ref());
inner.extend_from_slice(b">");
}
Ok(Event::Text(ref t)) => {
inner.extend_from_slice(t.as_ref());
}
Ok(Event::Eof) => break,
Err(e) => return Err(e),
_ => {}
}
}
Ok(inner)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn local_name_with_namespace_prefix() {
assert_eq!(local_name(b"a:body"), b"body");
}
#[test]
fn local_name_without_namespace() {
assert_eq!(local_name(b"name"), b"name");
}
#[test]
fn local_name_with_p_prefix() {
assert_eq!(local_name(b"p:sp"), b"sp");
}
#[test]
fn local_name_empty_input() {
assert_eq!(local_name(b""), b"");
}
#[test]
fn local_name_str_with_namespace() {
assert_eq!(local_name_str(b"p:sldIdLst"), "sldIdLst");
}
#[test]
fn local_name_str_without_namespace() {
assert_eq!(local_name_str(b"sldIdLst"), "sldIdLst");
}
#[test]
fn attr_value_from_bytes_start() {
let xml = br#"<elem foo="bar" ns:baz="qux"/>"#;
let mut reader = Reader::from_reader(&xml[..]);
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Empty(ref e)) | Ok(Event::Start(ref e)) => {
let val = attr_value(e, b"foo").unwrap();
assert_eq!(val.as_deref(), Some("bar"));
let val2 = attr_value(e, b"baz").unwrap();
assert_eq!(val2.as_deref(), Some("qux"));
let val3 = attr_value(e, b"missing").unwrap();
assert!(val3.is_none());
break;
}
Ok(Event::Eof) => break,
_ => {}
}
}
}
}