pub fn escape_text(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for ch in s.chars() {
match ch {
'&' => out.push_str("&"),
'<' => out.push_str("<"),
'>' => out.push_str(">"),
'"' => out.push_str("""),
_ => out.push(ch),
}
}
out
}
pub fn escape_url(s: &str) -> String {
let bytes = s.as_bytes();
let mut out = String::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
let b = bytes[i];
let safe = b.is_ascii_alphanumeric()
|| matches!(
b,
b'-'
| b'_'
| b'.'
| b'~'
| b'!'
| b'$'
| b'\''
| b'('
| b')'
| b'*'
| b','
| b';'
| b'='
| b'+'
| b':'
| b'@'
| b'/'
| b'?'
| b'#'
);
if b == b'%' && i + 2 < bytes.len() && bytes[i + 1].is_ascii_hexdigit() && bytes[i + 2].is_ascii_hexdigit() {
out.push('%');
out.push(bytes[i + 1] as char);
out.push(bytes[i + 2] as char);
i += 3;
continue;
}
if b == b'&' {
out.push('&');
} else if safe {
out.push(b as char);
} else {
out.push_str(&format!("%{:02X}", b));
}
i += 1;
}
out
}
pub fn escape_attr(s: &str) -> String {
let mut out = String::with_capacity(s.len());
for ch in s.chars() {
match ch {
'&' => out.push_str("&"),
'"' => out.push_str("""),
'<' => out.push_str("<"),
'>' => out.push_str(">"),
_ => out.push(ch),
}
}
out
}