xml/reader/parser/
inside_opening_tag.rs

1use crate::attribute::OwnedAttribute;
2use crate::common::{is_name_start_char, is_whitespace_char};
3use crate::namespace;
4use crate::reader::error::SyntaxError;
5
6use crate::reader::lexer::Token;
7
8use super::{OpeningTagSubstate, PullParser, QualifiedNameTarget, Result, State};
9
10impl PullParser {
11    pub fn inside_opening_tag(&mut self, t: Token, s: OpeningTagSubstate) -> Option<Result> {
12        let max_attrs = self.config.max_attributes;
13        match s {
14            OpeningTagSubstate::InsideName => self.read_qualified_name(t, QualifiedNameTarget::OpeningTagNameTarget, |this, token, name| {
15                match name.prefix_ref() {
16                    Some(prefix) if prefix == namespace::NS_XML_PREFIX ||
17                                    prefix == namespace::NS_XMLNS_PREFIX =>
18                        Some(this.error(SyntaxError::InvalidNamePrefix(prefix.into()))),
19                    _ => {
20                        this.data.element_name = Some(name.clone());
21                        match token {
22                            Token::TagEnd => this.emit_start_element(false),
23                            Token::EmptyTagEnd => this.emit_start_element(true),
24                            Token::Character(c) if is_whitespace_char(c) => this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::InsideTag)),
25                            _ => {
26                                debug_assert!(false, "unreachable");
27                                None
28                            },
29                        }
30                    }
31                }
32            }),
33
34            OpeningTagSubstate::InsideTag => match t {
35                Token::TagEnd => self.emit_start_element(false),
36                Token::EmptyTagEnd => self.emit_start_element(true),
37                Token::Character(c) if is_whitespace_char(c) => None, // skip whitespace
38                Token::Character(c) if is_name_start_char(c) => {
39                    if self.buf.len() > self.config.max_name_length {
40                        return Some(self.error(SyntaxError::ExceededConfiguredLimit));
41                    }
42                    self.buf.push(c);
43                    self.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::InsideAttributeName))
44                },
45                _ => Some(self.error(SyntaxError::UnexpectedTokenInOpeningTag(t))),
46            },
47
48            OpeningTagSubstate::InsideAttributeName => self.read_qualified_name(t, QualifiedNameTarget::AttributeNameTarget, |this, token, name| {
49                // check that no attribute with such name is already present
50                // if there is one, XML is not well-formed
51                if this.data.attributes.contains(&name) {
52                    return Some(this.error(SyntaxError::RedefinedAttribute(name.to_string().into())))
53                }
54
55                this.data.attr_name = Some(name);
56                match token {
57                    Token::EqualsSign => this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::InsideAttributeValue)),
58                    Token::Character(c) if is_whitespace_char(c) => this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::AfterAttributeName)),
59                    _ => Some(this.error(SyntaxError::UnexpectedTokenInOpeningTag(t))) // likely unreachable
60                }
61            }),
62
63            OpeningTagSubstate::AfterAttributeName => match t {
64                Token::EqualsSign => self.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::InsideAttributeValue)),
65                Token::Character(c) if is_whitespace_char(c) => None,
66                _ => Some(self.error(SyntaxError::UnexpectedTokenInOpeningTag(t)))
67            },
68
69            OpeningTagSubstate::InsideAttributeValue => self.read_attribute_value(t, |this, value| {
70                let name = this.data.take_attr_name()?;  // will always succeed here
71                match name.prefix_ref() {
72                    // declaring a new prefix; it is sufficient to check prefix only
73                    // because "xmlns" prefix is reserved
74                    Some(namespace::NS_XMLNS_PREFIX) => {
75                        let ln = &*name.local_name;
76                        if ln == namespace::NS_XMLNS_PREFIX {
77                            Some(this.error(SyntaxError::CannotRedefineXmlnsPrefix))
78                        } else if ln == namespace::NS_XML_PREFIX && &*value != namespace::NS_XML_URI {
79                            Some(this.error(SyntaxError::CannotRedefineXmlPrefix))
80                        } else if value.is_empty() {
81                            Some(this.error(SyntaxError::CannotUndefinePrefix(ln.into())))
82                        } else {
83                            this.nst.put(name.local_name.clone(), value);
84                            this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::AfterAttributeValue))
85                        }
86                    },
87
88                    // declaring default namespace
89                    None if &*name.local_name == namespace::NS_XMLNS_PREFIX =>
90                        match &*value {
91                            namespace::NS_XMLNS_PREFIX | namespace::NS_XML_PREFIX | namespace::NS_XML_URI | namespace::NS_XMLNS_URI =>
92                                Some(this.error(SyntaxError::InvalidDefaultNamespace(value.into()))),
93                            _ => {
94                                this.nst.put(namespace::NS_NO_PREFIX, value.clone());
95                                this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::AfterAttributeValue))
96                            }
97                        },
98
99                    // regular attribute
100                    _ => {
101                        if this.data.attributes.len() >= max_attrs {
102                            return Some(this.error(SyntaxError::ExceededConfiguredLimit));
103                        }
104                        this.data.attributes.push(OwnedAttribute { name, value });
105                        this.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::AfterAttributeValue))
106                    },
107                }
108            }),
109
110            OpeningTagSubstate::AfterAttributeValue => match t {
111                Token::Character(c) if is_whitespace_char(c) => {
112                    self.into_state_continue(State::InsideOpeningTag(OpeningTagSubstate::InsideTag))
113                },
114                Token::TagEnd => self.emit_start_element(false),
115                Token::EmptyTagEnd => self.emit_start_element(true),
116                _ => Some(self.error(SyntaxError::UnexpectedTokenInOpeningTag(t))),
117            },
118        }
119    }
120}