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