mod docx;
mod opc;
pub(crate) use docx::{to_docx, try_to_docx};
fn is_xml_legal_char(c: char) -> bool {
matches!(c, '\t' | '\n' | '\r')
|| matches!(
c as u32,
0x20..=0xD7FF | 0xE000..=0xFFFD | 0x10000..=0x10FFFF
)
}
pub(crate) fn esc_text(s: &str) -> String {
let mut o = String::with_capacity(s.len());
for c in s.chars() {
match c {
'&' => o.push_str("&"),
'<' => o.push_str("<"),
'>' => o.push_str(">"),
c if !is_xml_legal_char(c) => {}
c => o.push(c),
}
}
o
}
pub(crate) fn esc_attr(s: &str) -> String {
let mut o = String::with_capacity(s.len());
for c in s.chars() {
match c {
'&' => o.push_str("&"),
'<' => o.push_str("<"),
'>' => o.push_str(">"),
'"' => o.push_str("""),
c if !is_xml_legal_char(c) => {}
c => o.push(c),
}
}
o
}
#[cfg(test)]
mod tests {
use super::{esc_attr, esc_text};
#[test]
fn escapers_strip_xml_illegal_controls() {
assert_eq!(esc_text("a\u{0B}b\u{1F}c"), "abc");
assert_eq!(esc_attr("u\u{0C}r\u{01}l"), "url");
assert_eq!(esc_text("a&<>b"), "a&<>b");
assert_eq!(esc_attr("\"x\"&"), ""x"&");
assert_eq!(esc_text("a\tb\nc\r"), "a\tb\nc\r");
}
#[test]
fn escapers_strip_xml_forbidden_scalars() {
assert_eq!(esc_text("a\u{FFFE}b\u{FFFF}c"), "abc");
assert_eq!(esc_attr("a\u{FFFE}\"b\u{FFFF}"), "a"b");
}
}