use std::char;
use crate::xml::common::{is_name_char, is_name_start_char, is_whitespace_str};
use crate::xml::reader::lexer::Token;
use crate::xml::reader::parser::{ParserOutcome, PullParser, State};
impl PullParser {
pub fn inside_reference(&mut self, t: Token, prev_st: State) -> Option<ParserOutcome> {
match t {
Token::Character(c)
if !self.data.ref_data.is_empty() && is_name_char(c)
|| self.data.ref_data.is_empty() && (is_name_start_char(c) || c == '#') =>
{
self.data.ref_data.push(c);
None
}
Token::ReferenceEnd => {
let name = self.data.take_ref_data();
let name_len = name.len(); let c = match &name[..] {
"lt" => Ok('<'.to_string()),
"gt" => Ok('>'.to_string()),
"amp" => Ok('&'.to_string()),
"apos" => Ok('\''.to_string()),
"quot" => Ok('"'.to_string()),
"" => Err(self_error!(self; "Encountered empty entity")),
_ if name_len > 2 && name.starts_with("#x") => {
let num_str = &name[2..name_len];
if num_str == "0" {
Err(self_error!(self; "Null character entity is not allowed"))
} else {
match u32::from_str_radix(num_str, 16)
.ok()
.and_then(char::from_u32)
{
Some(c) => Ok(c.to_string()),
None => Err(
self_error!(self; "Invalid hexadecimal character number in an entity: {}", name),
),
}
}
}
_ if name_len > 1 && name.starts_with('#') => {
let num_str = &name[1..name_len];
if num_str == "0" {
Err(self_error!(self; "Null character entity is not allowed"))
} else {
match num_str.parse::<u32>().ok().and_then(char::from_u32) {
Some(c) => Ok(c.to_string()),
None => Err(
self_error!(self; "Invalid decimal character number in an entity: {}", name),
),
}
}
}
_ => {
if let Some(v) = self.config.extra_entities.get(&name) {
Ok(v.clone())
} else {
Err(self_error!(self; "Unexpected entity: {}", name))
}
}
};
match c {
Ok(c) => {
self.buf.push_str(&c);
if prev_st == State::OutsideTag && !is_whitespace_str(&c) {
self.inside_whitespace = false;
}
self.as_state_continue(prev_st)
}
Err(e) => Some(e),
}
}
_ => Some(self_error!(self; "Unexpected token inside an entity: {}", t)),
}
}
}