xml/reader/parser/
inside_reference.rs

1use std::char;
2
3use common::{is_name_start_char, is_name_char, is_whitespace_str};
4
5use reader::lexer::Token;
6
7use super::{Result, PullParser, State};
8
9impl PullParser {
10    pub fn inside_reference(&mut self, t: Token, prev_st: State) -> Option<Result> {
11        match t {
12            Token::Character(c) if !self.data.ref_data.is_empty() && is_name_char(c) ||
13                             self.data.ref_data.is_empty() && (is_name_start_char(c) || c == '#') => {
14                self.data.ref_data.push(c);
15                None
16            }
17
18            Token::ReferenceEnd => {
19                // TODO: check for unicode correctness
20                let name = self.data.take_ref_data();
21                let name_len = name.len();  // compute once
22                let c = match &name[..] {
23                    "lt"   => Ok('<'.to_string()),
24                    "gt"   => Ok('>'.to_string()),
25                    "amp"  => Ok('&'.to_string()),
26                    "apos" => Ok('\''.to_string()),
27                    "quot" => Ok('"'.to_string()),
28                    ""     => Err(self_error!(self; "Encountered empty entity")),
29                    _ if name_len > 2 && name.starts_with("#x") => {
30                        let num_str = &name[2..name_len];
31                        if num_str == "0" {
32                            Err(self_error!(self; "Null character entity is not allowed"))
33                        } else {
34                            match u32::from_str_radix(num_str, 16).ok().and_then(char::from_u32) {
35                                Some(c) => Ok(c.to_string()),
36                                None    => Err(self_error!(self; "Invalid hexadecimal character number in an entity: {}", name))
37                            }
38                        }
39                    }
40                    _ if name_len > 1 && name.starts_with('#') => {
41                        let num_str = &name[1..name_len];
42                        if num_str == "0" {
43                            Err(self_error!(self; "Null character entity is not allowed"))
44                        } else {
45                            match u32::from_str_radix(num_str, 10).ok().and_then(char::from_u32) {
46                                Some(c) => Ok(c.to_string()),
47                                None    => Err(self_error!(self; "Invalid decimal character number in an entity: {}", name))
48                            }
49                        }
50                    },
51                    _ => {
52                        if let Some(v) = self.config.extra_entities.get(&name) {
53                            Ok(v.clone())
54                        } else {
55                            Err(self_error!(self; "Unexpected entity: {}", name))
56                        }
57                    }
58                };
59                match c {
60                    Ok(c) => {
61                        self.buf.push_str(&c);
62                        if prev_st == State::OutsideTag && !is_whitespace_str(&c) {
63                            self.inside_whitespace = false;
64                        }
65                        self.into_state_continue(prev_st)
66                    }
67                    Err(e) => Some(e)
68                }
69            }
70
71            _ => Some(self_error!(self; "Unexpected token inside an entity: {}", t))
72        }
73    }
74}