1extern crate alloc;
2
3use core::fmt;
4use core::result;
5
6use alloc::string::String;
7use alloc::vec::Vec;
8
9use crate::attribute::Attribute;
10use crate::common;
11use crate::common::XmlVersion;
12use crate::escape::{AttributeEscapes, Escaped, PcDataEscapes};
13use crate::name::{Name, OwnedName};
14use crate::namespace::{NamespaceStack, NS_EMPTY_URI, NS_NO_PREFIX, NS_XMLNS_PREFIX, NS_XML_PREFIX};
15
16use crate::writer::config::EmitterConfig;
17
18macro_rules! write {
19 ($dst:expr, $($arg:tt)*) => {
20 $dst.push_str(&alloc::format!($($arg)*))
21 };
22}
23
24#[derive(Debug)]
26pub enum EmitterError {
27 Io(String),
29
30 DocumentStartAlreadyEmitted,
32
33 LastElementNameNotAvailable,
35
36 EndElementNameIsNotEqualToLastStartElementName,
39
40 EndElementNameIsNotSpecified,
43}
44
45impl fmt::Display for EmitterError {
46 #[cold]
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 f.write_str("emitter error: ")?;
49 match self {
50 EmitterError::Io(e) => f.write_str(&alloc::format!("I/O error: {e}")),
51 EmitterError::DocumentStartAlreadyEmitted => f.write_str("document start event has already been emitted"),
52 EmitterError::LastElementNameNotAvailable => f.write_str("last element name is not available"),
53 EmitterError::EndElementNameIsNotEqualToLastStartElementName => f.write_str("end element name is not equal to last start element name"),
54 EmitterError::EndElementNameIsNotSpecified => f.write_str("end element name is not specified and can't be inferred"),
55 }
56 }
57}
58
59pub type Result<T, E = EmitterError> = result::Result<T, E>;
61
62pub struct Emitter {
65 config: EmitterConfig,
66
67 nst: NamespaceStack,
68
69 indent_level: usize,
70 indent_stack: Vec<IndentFlags>,
71
72 element_names: Vec<OwnedName>,
73
74 start_document_emitted: bool,
75 just_wrote_start_element: bool,
76}
77
78impl Emitter {
79 pub fn new(config: EmitterConfig) -> Emitter {
80 let mut indent_stack = Vec::with_capacity(16);
81 indent_stack.push(IndentFlags::WroteNothing);
82
83 Emitter {
84 config,
85
86 nst: NamespaceStack::empty(),
87
88 indent_level: 0,
89 indent_stack,
90
91 element_names: Vec::new(),
92
93 start_document_emitted: false,
94 just_wrote_start_element: false,
95 }
96 }
97}
98
99#[derive(Copy, Clone, Eq, PartialEq, Debug)]
100enum IndentFlags {
101 WroteNothing,
102 WroteMarkup,
103 WroteText,
104}
105
106impl Emitter {
107 #[inline]
109 pub fn namespace_stack_mut(&mut self) -> &mut NamespaceStack {
110 &mut self.nst
111 }
112
113 #[inline]
114 fn wrote_text(&self) -> bool {
115 self.indent_stack.last().map_or(false, |&e| e == IndentFlags::WroteText)
116 }
117
118 #[inline]
119 fn wrote_markup(&self) -> bool {
120 self.indent_stack.last().map_or(false, |&e| e == IndentFlags::WroteMarkup)
121 }
122
123 #[inline]
124 fn set_wrote_text(&mut self) {
125 if let Some(e) = self.indent_stack.last_mut() {
126 *e = IndentFlags::WroteText;
127 }
128 }
129
130 #[inline]
131 fn set_wrote_markup(&mut self) {
132 if let Some(e) = self.indent_stack.last_mut() {
133 *e = IndentFlags::WroteMarkup;
134 }
135 }
136
137 fn write_newline(&mut self, target: &mut String, level: usize){
138 target.push_str(&self.config.line_separator);
139 for _ in 0..level {
140 target.push_str(&self.config.indent_string);
141 }
142 }
143
144 fn before_markup(&mut self, target: &mut String) {
145 if self.config.perform_indent && !self.wrote_text() &&
146 (self.indent_level > 0 || self.wrote_markup()) {
147 let indent_level = self.indent_level;
148 self.write_newline(target, indent_level);
149 if self.indent_level > 0 && self.config.indent_string.len() > 0 {
150 self.after_markup();
151 }
152 }
153 }
154
155 fn after_markup(&mut self) {
156 self.set_wrote_markup();
157 }
158
159 fn before_start_element(&mut self, target: &mut String) {
160 self.before_markup(target);
161 self.indent_stack.push(IndentFlags::WroteNothing);
162 }
163
164 fn after_start_element(&mut self) {
165 self.after_markup();
166 self.indent_level += 1;
167 }
168
169 fn before_end_element(&mut self, target: &mut String) {
170 if self.config.perform_indent && self.indent_level > 0 && self.wrote_markup() &&
171 !self.wrote_text() {
172 let indent_level = self.indent_level;
173 self.write_newline(target, indent_level - 1)
174 }
175 }
176
177 fn after_end_element(&mut self) {
178 if self.indent_level > 0 {
179 self.indent_level -= 1;
180 self.indent_stack.pop();
181 }
182 self.set_wrote_markup();
183 }
184
185 fn after_text(&mut self) {
186 self.set_wrote_text();
187 }
188
189 pub fn emit_start_document(&mut self, target: &mut String,
190 version: XmlVersion,
191 encoding: &str,
192 standalone: Option<bool>) -> Result<()> {
193 if self.start_document_emitted {
194 return Err(EmitterError::DocumentStartAlreadyEmitted);
195 }
196 self.start_document_emitted = true;
197
198 self.before_markup(target);
199 let result = {
200 let mut write = move || {
201 write!(target, "<?xml version=\"{version}\" encoding=\"{encoding}\"");
202
203 if let Some(standalone) = standalone {
204 write!(target, " standalone=\"{}\"", if standalone { "yes" } else { "no" });
205 }
206
207 write!(target, "?>");
208
209 Ok(())
210 };
211 write()
212 };
213 self.after_markup();
214
215 result
216 }
217
218 fn check_document_started(&mut self, target: &mut String) -> Result<()> {
219 if !self.start_document_emitted && self.config.write_document_declaration {
220 self.emit_start_document(target, common::XmlVersion::Version10, "UTF-8", None)
221 } else {
222 Ok(())
223 }
224 }
225
226 fn fix_non_empty_element(&mut self, target: &mut String) {
227 if self.config.normalize_empty_elements && self.just_wrote_start_element {
228 self.just_wrote_start_element = false;
229 target.push_str(">")
230 }
231 }
232
233 pub fn emit_processing_instruction(&mut self,
234 target: &mut String,
235 name: &str,
236 data: Option<&str>) -> Result<()> {
237 self.check_document_started(target)?;
238 self.fix_non_empty_element(target);
239
240 self.before_markup(target);
241
242 let result = {
243 let mut write = move || {
244 write!(target, "<?{name}");
245
246 if let Some(data) = data {
247 write!(target, " {data}");
248 }
249
250 write!(target, "?>");
251
252 Ok(())
253 };
254 write()
255 };
256
257 self.after_markup();
258
259 result
260 }
261
262 #[track_caller]
263 fn emit_start_element_initial(&mut self, target: &mut String,
264 name: Name<'_>,
265 attributes: &[Attribute<'_>]) -> Result<()>
266 {
267 self.check_document_started(target)?;
268 self.fix_non_empty_element(target);
269 self.before_start_element(target);
270 write!(target, "<{}", name.repr_display());
271 self.emit_current_namespace_attributes(target);
272 self.emit_attributes(target, attributes);
273 self.after_start_element();
274 Ok(())
275 }
276
277 #[track_caller]
278 pub fn emit_start_element(&mut self, target: &mut String,
279 name: Name<'_>,
280 attributes: &[Attribute<'_>]) -> Result<()>
281 {
282 if self.config.keep_element_names_stack {
283 self.element_names.push(name.to_owned());
284 }
285
286 self.emit_start_element_initial(target, name, attributes)?;
287 self.just_wrote_start_element = true;
288
289 if !self.config.normalize_empty_elements {
290 write!(target, ">");
291 }
292
293 Ok(())
294 }
295
296 #[track_caller]
297 pub fn emit_current_namespace_attributes(&mut self, target: &mut String)
298 {
299 for (prefix, uri) in self.nst.peek() {
300 match prefix {
301 NS_XMLNS_PREFIX | NS_XML_PREFIX => (),
303 NS_NO_PREFIX => if uri != NS_EMPTY_URI {
307 write!(target, " xmlns=\"{uri}\"")
308 },
309 prefix => write!(target, " xmlns:{prefix}=\"{uri}\"")
311 };
312 }
313 }
314
315 pub fn emit_attributes(&mut self, target: &mut String,
316 attributes: &[Attribute<'_>]) {
317 for attr in attributes {
318 write!(target, " {}=\"", attr.name.repr_display());
319 if self.config.perform_escaping {
320 write!(target, "{}", Escaped::<AttributeEscapes>::new(attr.value));
321 } else {
322 write!(target, "{}", attr.value);
323 }
324 write!(target, "\"");
325 }
326 }
327
328 pub fn emit_end_element(&mut self, target: &mut String,
329 name: Option<Name<'_>>) -> Result<()> {
330 let owned_name = if self.config.keep_element_names_stack {
331 Some(self.element_names.pop().ok_or(EmitterError::LastElementNameNotAvailable)?)
332 } else {
333 None
334 };
335
336 if let Some(ref last_name) = owned_name {
338 if let Some(ref name) = name {
339 if last_name.borrow() != *name {
340 return Err(EmitterError::EndElementNameIsNotEqualToLastStartElementName);
341 }
342 }
343 }
344
345 if let Some(name) = owned_name.as_ref().map(|n| n.borrow()).or(name) {
346 Ok(if self.config.normalize_empty_elements && self.just_wrote_start_element {
347 self.just_wrote_start_element = false;
348 let termination = if self.config.pad_self_closing { " />" } else { "/>" };
349 target.push_str(termination);
350 self.after_end_element();
351 } else {
352 self.just_wrote_start_element = false;
353
354 self.before_end_element(target);
355 write!(target, "</{}>", name.repr_display());
356 self.after_end_element();
357 })
358 } else {
359 Err(EmitterError::EndElementNameIsNotSpecified)
360 }
361 }
362
363 pub fn emit_cdata(&mut self, target: &mut String, content: &str) {
364 self.fix_non_empty_element(target);
365 if self.config.cdata_to_characters {
366 self.emit_characters(target, content)
367 } else {
368 target.push_str("<![CDATA[");
370 target.push_str(content);
371 target.push_str("]]>");
372
373 self.after_text();
374 }
375 }
376
377 pub fn emit_characters(&mut self, target: &mut String, content: &str) {
378 let _ = self.check_document_started(target);
379 self.fix_non_empty_element(target);
380
381 if self.config.perform_escaping {
382 write!(target, "{}", Escaped::<PcDataEscapes>::new(content));
383 } else {
384 target.push_str(content);
385 }
386
387 self.after_text();
388 }
389
390 pub fn emit_comment(&mut self, target: &mut String, content: &str) -> Result<()> {
391 self.fix_non_empty_element(target);
392
393 let autopad_comments = self.config.autopad_comments;
396 let write = move |target: &mut String| -> Result<()> {
397 target.push_str("<!--");
398
399 if autopad_comments && !content.starts_with(char::is_whitespace) {
400 target.push_str(" ");
401 }
402
403 target.push_str(content);
404
405 if autopad_comments && !content.ends_with(char::is_whitespace) {
406 target.push_str(" ");
407 }
408
409 target.push_str("-->");
410
411 Ok(())
412 };
413
414 self.before_markup(target);
415 let result = write(target);
416 self.after_markup();
417
418 result
419 }
420}