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