xml_no_std/reader/parser/
inside_declaration.rs1extern crate alloc;
2
3use alloc::string::ToString;
4
5use crate::common::{is_whitespace_char, XmlVersion};
6use crate::reader::error::SyntaxError;
7use crate::reader::events::XmlEvent;
8use crate::reader::lexer::Token;
9use crate::util::Encoding;
10
11use super::{
12 DeclarationSubstate, Encountered, PullParser, QualifiedNameTarget, Result, State,
13 DEFAULT_VERSION,
14};
15
16impl PullParser {
17 #[inline(never)]
18 fn emit_start_document(&mut self) -> Option<Result> {
19 debug_assert!(self.encountered == Encountered::None);
20 self.encountered = Encountered::Declaration;
21
22 let version = self.data.version;
23 let encoding = self.data.take_encoding();
24 let standalone = self.data.standalone;
25
26 if let Some(new_encoding) = encoding.as_deref() {
27 let new_encoding = match new_encoding.parse() {
28 Ok(e) => e,
29 Err(_) if self.config.ignore_invalid_encoding_declarations => Encoding::Latin1,
30 Err(_) => return Some(self.error(SyntaxError::UnsupportedEncoding(new_encoding.into()))),
31 };
32 let current_encoding = self.lexer.encoding();
33 if current_encoding != new_encoding {
34 let set = match (current_encoding, new_encoding) {
35 (Encoding::Unknown | Encoding::Default, new) if new != Encoding::Utf16 => new,
36 (Encoding::Utf16Be | Encoding::Utf16Le, Encoding::Utf16) => current_encoding,
37 _ if self.config.ignore_invalid_encoding_declarations => current_encoding,
38 _ => return Some(self.error(SyntaxError::ConflictingEncoding(new_encoding, current_encoding))),
39 };
40 self.lexer.set_encoding(set);
41 }
42 }
43
44 let current_encoding = self.lexer.encoding();
45 self.into_state_emit(State::OutsideTag, Ok(XmlEvent::StartDocument {
46 version: version.unwrap_or(DEFAULT_VERSION),
47 encoding: encoding.unwrap_or_else(move || current_encoding.to_string()),
48 standalone
49 }))
50 }
51
52 pub fn inside_declaration(&mut self, t: Token, s: DeclarationSubstate) -> Option<Result> {
54
55 match s {
56 DeclarationSubstate::BeforeVersion => match t {
57 Token::Character('v') => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideVersion)),
58 Token::Character(c) if is_whitespace_char(c) => None, _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
60 },
61
62 DeclarationSubstate::InsideVersion => self.read_qualified_name(t, QualifiedNameTarget::AttributeNameTarget, |this, token, name| {
63 match &*name.local_name {
64 "ersion" if name.namespace.is_none() =>
65 this.into_state_continue(State::InsideDeclaration(
66 if token == Token::EqualsSign {
67 DeclarationSubstate::InsideVersionValue
68 } else {
69 DeclarationSubstate::AfterVersion
70 }
71 )),
72 _ => Some(this.error(SyntaxError::UnexpectedNameInsideXml(name.to_string().into()))),
73 }
74 }),
75
76 DeclarationSubstate::AfterVersion => match t {
77 Token::EqualsSign => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideVersionValue)),
78 Token::Character(c) if is_whitespace_char(c) => None,
79 _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
80 },
81
82 DeclarationSubstate::InsideVersionValue => self.read_attribute_value(t, |this, value| {
83 this.data.version = match &*value {
84 "1.0" => Some(XmlVersion::Version10),
85 "1.1" => Some(XmlVersion::Version11),
86 _ => None
87 };
88 if this.data.version.is_some() {
89 this.into_state_continue(State::InsideDeclaration(DeclarationSubstate::AfterVersionValue))
90 } else {
91 Some(this.error(SyntaxError::UnexpectedXmlVersion(value.into())))
92 }
93 }),
94
95 DeclarationSubstate::AfterVersionValue => match t {
96 Token::Character(c) if is_whitespace_char(c) => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::BeforeEncoding)),
97 Token::ProcessingInstructionEnd => self.emit_start_document(),
98 _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
99 },
100
101 DeclarationSubstate::BeforeEncoding => match t {
102 Token::Character('e') => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideEncoding)),
103 Token::Character('s') => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideStandaloneDecl)),
104 Token::ProcessingInstructionEnd => self.emit_start_document(),
105 Token::Character(c) if is_whitespace_char(c) => None, _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
107 },
108
109 DeclarationSubstate::InsideEncoding => self.read_qualified_name(t, QualifiedNameTarget::AttributeNameTarget, |this, token, name| {
110 match &*name.local_name {
111 "ncoding" if name.namespace.is_none() =>
112 this.into_state_continue(State::InsideDeclaration(
113 if token == Token::EqualsSign { DeclarationSubstate::InsideEncodingValue } else { DeclarationSubstate::AfterEncoding }
114 )),
115 _ => Some(this.error(SyntaxError::UnexpectedName(name.to_string().into())))
116 }
117 }),
118
119 DeclarationSubstate::AfterEncoding => match t {
120 Token::EqualsSign => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideEncodingValue)),
121 Token::Character(c) if is_whitespace_char(c) => None,
122 _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
123 },
124
125 DeclarationSubstate::InsideEncodingValue => self.read_attribute_value(t, |this, value| {
126 this.data.encoding = Some(value);
127 this.into_state_continue(State::InsideDeclaration(DeclarationSubstate::AfterEncodingValue))
128 }),
129
130 DeclarationSubstate::AfterEncodingValue => match t {
131 Token::Character(c) if is_whitespace_char(c) => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::BeforeStandaloneDecl)),
132 Token::ProcessingInstructionEnd => self.emit_start_document(),
133 _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
134 },
135
136 DeclarationSubstate::BeforeStandaloneDecl => match t {
137 Token::Character('s') => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideStandaloneDecl)),
138 Token::ProcessingInstructionEnd => self.emit_start_document(),
139 Token::Character(c) if is_whitespace_char(c) => None, _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
141 },
142
143 DeclarationSubstate::InsideStandaloneDecl => self.read_qualified_name(t, QualifiedNameTarget::AttributeNameTarget, |this, token, name| {
144 match &*name.local_name {
145 "tandalone" if name.namespace.is_none() =>
146 this.into_state_continue(State::InsideDeclaration(
147 if token == Token::EqualsSign {
148 DeclarationSubstate::InsideStandaloneDeclValue
149 } else {
150 DeclarationSubstate::AfterStandaloneDecl
151 }
152 )),
153 _ => Some(this.error(SyntaxError::UnexpectedName(name.to_string().into()))),
154 }
155 }),
156
157 DeclarationSubstate::AfterStandaloneDecl => match t {
158 Token::EqualsSign => self.into_state_continue(State::InsideDeclaration(DeclarationSubstate::InsideStandaloneDeclValue)),
159 Token::Character(c) if is_whitespace_char(c) => None,
160 _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
161 },
162
163 DeclarationSubstate::InsideStandaloneDeclValue => self.read_attribute_value(t, |this, value| {
164 let standalone = match &*value {
165 "yes" => Some(true),
166 "no" => Some(false),
167 _ => None
168 };
169 if standalone.is_some() {
170 this.data.standalone = standalone;
171 this.into_state_continue(State::InsideDeclaration(DeclarationSubstate::AfterStandaloneDeclValue))
172 } else {
173 Some(this.error(SyntaxError::InvalidStandaloneDeclaration(value.into())))
174 }
175 }),
176
177 DeclarationSubstate::AfterStandaloneDeclValue => match t {
178 Token::ProcessingInstructionEnd => self.emit_start_document(),
179 Token::Character(c) if is_whitespace_char(c) => None, _ => Some(self.error(SyntaxError::UnexpectedToken(t))),
181 },
182 }
183 }
184}