blob: 60026d557275fff177ed3d96761591c1b3aa82f6 [file] [log] [blame]
use std::char;
use common::{is_name_start_char, is_name_char, is_whitespace_str};
use reader::lexer::Token;
use super::{Result, PullParser, State};
impl PullParser {
pub fn inside_reference(&mut self, t: Token, prev_st: State) -> Option<Result> {
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 => {
// TODO: check for unicode correctness
let name = self.data.take_ref_data();
let name_len = name.len(); // compute once
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 {
if self.config.replace_unknown_entity_references {
match u32::from_str_radix(num_str, 16).ok().map(|i| char::from_u32(i).unwrap_or('\u{fffd}')) {
Some(c) => Ok(c.to_string()),
None => Err(self_error!(self; "Invalid hexadecimal character number in an entity: {}", name))
}
} 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 {
if self.config.replace_unknown_entity_references {
match u32::from_str_radix(num_str, 10).ok().map(|i| char::from_u32(i).unwrap_or('\u{fffd}')) {
Some(c) => Ok(c.to_string()),
None => Err(self_error!(self; "Invalid decimal character number in an entity: {}", name))
}
}
else {
match u32::from_str_radix(num_str, 10).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.into_state_continue(prev_st)
}
Err(e) => Some(e)
}
}
_ => Some(self_error!(self; "Unexpected token inside an entity: {}", t))
}
}
}