use std::char;
use std::io::{self, Write};
use crate::io_support::write_char;
pub fn encode_minimal(s: &str) -> String {
let mut writer = Vec::with_capacity((s.len() / 3 + 1) * 4);
encode_minimal_w(s, &mut writer).unwrap();
String::from_utf8(writer).expect("impossible invalid UTF-8 in output")
}
pub fn encode_minimal_w<W: Write>(s: &str, writer: &mut W) -> io::Result<()> {
for c in s.chars() {
match get_entity(c) {
None => write_char(writer, c)?,
Some(entity) => writer.write_all(entity.as_bytes())?,
}
}
Ok(())
}
pub fn encode_attribute(s: &str) -> String {
let mut writer = Vec::with_capacity(s.len() * 3);
encode_attribute_w(s, &mut writer).unwrap();
String::from_utf8(writer).unwrap()
}
pub fn encode_attribute_w<W: Write>(s: &str, writer: &mut W) -> io::Result<()> {
for c in s.chars() {
let b = c as usize;
let res = match get_entity(c) {
Some(entity) => writer.write_all(entity.as_bytes()),
None => {
if b < 256 && (b > 127 || !is_ascii_alnum(c)) {
write_hex(writer, c)
} else {
write_char(writer, c)
}
}
};
res?;
}
Ok(())
}
fn get_entity(c: char) -> Option<&'static str> {
match crate::MINIMAL_ENTITIES.binary_search_by(|&(ec, _)| ec.cmp(&c)) {
Err(..) => None,
Ok(idx) => {
let (_, e) = crate::MINIMAL_ENTITIES[idx];
Some(e)
}
}
}
fn write_hex<W: Write>(writer: &mut W, c: char) -> io::Result<()> {
let hex = b"0123456789ABCDEF";
writer.write_all(b"&#x")?;
let n = c as u8;
let bytes = [
hex[((n & 0xF0) >> 4) as usize],
hex[(n & 0x0F) as usize],
b';',
];
writer.write_all(&bytes)
}
fn is_ascii_alnum(c: char) -> bool {
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
}