use jetscii::{bytes, BytesConst};
use lazy_static::lazy_static;
use std::borrow::Cow;
pub fn xml_escape<'a>(raw: &'a str) -> Cow<'a, str> {
lazy_static! {
static ref ESCAPE_BYTES: BytesConst = bytes!(b'<', b'>', b'&', b'\'', b'"');
}
let bytes = raw.as_bytes();
if let Some(off) = ESCAPE_BYTES.find(bytes) {
let mut result = String::with_capacity(raw.len());
result.push_str(&raw[0..off]);
let mut pos = off + 1;
match bytes[pos - 1] {
b'<' => result.push_str("<"),
b'>' => result.push_str(">"),
b'&' => result.push_str("&"),
b'\'' => result.push_str("'"),
b'"' => result.push_str("""),
_ => unreachable!(),
}
while let Some(off) = ESCAPE_BYTES.find(&bytes[pos..]) {
result.push_str(&raw[pos..pos + off]);
pos += off + 1;
match bytes[pos - 1] {
b'<' => result.push_str("<"),
b'>' => result.push_str(">"),
b'&' => result.push_str("&"),
b'\'' => result.push_str("'"),
b'"' => result.push_str("""),
_ => unreachable!(),
}
}
result.push_str(&raw[pos..]);
Cow::Owned(result)
} else {
Cow::Borrowed(raw)
}
}
#[test]
fn test_escape() {
assert_eq!(xml_escape("< < <"), "< < <");
assert_eq!(
xml_escape("<script>alert('Hello XSS')</script>"),
"<script>alert('Hello XSS')</script>"
);
}